From 6059e8ee8b395aada3081487cf4f44ae97b140ff Mon Sep 17 00:00:00 2001 From: niftynei Date: Thu, 10 Jun 2021 12:54:08 -0500 Subject: [PATCH 01/56] liquidity-ads: import from spec Import the wires from spec. Here we go! --- channeld/channeld.c | 3 + common/test/Makefile | 1 + common/test/run-gossmap_local.c | 19 +-- devtools/create-gossipstore.c | 5 +- devtools/mkgossip.c | 21 ++- gossipd/gossip_generation.c | 5 +- gossipd/gossipd.c | 6 +- gossipd/routing.c | 10 +- openingd/dualopend.c | 3 + wire/extracted_peer_04_opt_will_fund.patch | 48 ++++++ wire/peer_printgen.c | 146 +++++++++++++++++- wire/peer_printgen.h | 5 +- wire/peer_wire.c | 2 + wire/peer_wire.csv | 18 +++ wire/peer_wiregen.c | 168 ++++++++++++++++++++- wire/peer_wiregen.h | 77 +++++++++- wire/test/run-peer-wire.c | 45 +++++- 17 files changed, 547 insertions(+), 35 deletions(-) create mode 100644 wire/extracted_peer_04_opt_will_fund.patch diff --git a/channeld/channeld.c b/channeld/channeld.c index 305de7e9eb34..d94b0c0752b0 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -2084,6 +2084,9 @@ static void peer_in(struct peer *peer, const u8 *msg) case WIRE_UPDATE_FEE: handle_peer_feechange(peer, msg); return; + case WIRE_UPDATE_BLOCKHEIGHT: + /* FIXME: do this! */ + break; case WIRE_REVOKE_AND_ACK: handle_peer_revoke_and_ack(peer, msg); return; diff --git a/common/test/Makefile b/common/test/Makefile index 596801d82d53..49be68ef49ba 100644 --- a/common/test/Makefile +++ b/common/test/Makefile @@ -48,6 +48,7 @@ common/test/run-route common/test/run-route-specific: \ common/test/run-gossmap_local: \ wire/fromwire.o \ wire/peer$(EXP)_wiregen.o \ + wire/tlvstream.o \ wire/towire.o check-units: $(COMMON_TEST_PROGRAMS:%=unittest/%) diff --git a/common/test/run-gossmap_local.c b/common/test/run-gossmap_local.c index 2e23651dfb32..c624f93d11b2 100644 --- a/common/test/run-gossmap_local.c +++ b/common/test/run-gossmap_local.c @@ -9,6 +9,7 @@ #include #include #include +#include /* AUTOGENERATED MOCKS START */ /* Generated stub for fromwire_bigsize */ @@ -18,25 +19,12 @@ bigsize_t fromwire_bigsize(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) void fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "fromwire_channel_id called!\n"); abort(); } -/* Generated stub for fromwire_tlv */ -bool fromwire_tlv(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, - const struct tlv_record_type *types UNNEEDED, size_t num_types UNNEEDED, - void *record UNNEEDED, struct tlv_field **fields UNNEEDED) -{ fprintf(stderr, "fromwire_tlv called!\n"); abort(); } -/* Generated stub for tlv_fields_valid */ -bool tlv_fields_valid(const struct tlv_field *fields UNNEEDED, size_t *err_index UNNEEDED) -{ fprintf(stderr, "tlv_fields_valid called!\n"); abort(); } /* Generated stub for towire_bigsize */ void towire_bigsize(u8 **pptr UNNEEDED, const bigsize_t val UNNEEDED) { fprintf(stderr, "towire_bigsize called!\n"); abort(); } /* Generated stub for towire_channel_id */ void towire_channel_id(u8 **pptr UNNEEDED, const struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "towire_channel_id called!\n"); abort(); } -/* Generated stub for towire_tlv */ -void towire_tlv(u8 **pptr UNNEEDED, - const struct tlv_record_type *types UNNEEDED, size_t num_types UNNEEDED, - const void *record UNNEEDED) -{ fprintf(stderr, "towire_tlv called!\n"); abort(); } /* Generated stub for type_to_string_ */ const char *type_to_string_(const tal_t *ctx UNNEEDED, const char *typename UNNEEDED, union printable_types u UNNEEDED) @@ -290,13 +278,16 @@ static void check_nannounce(const u8 *nannounce, u32 timestamp; u8 rgb_color[3], alias[32]; struct node_id node_id; + struct tlv_node_ann_tlvs *na_tlvs + = tlv_node_ann_tlvs_new(tmpctx); assert(fromwire_node_announcement(nannounce, nannounce, &sig, &features, ×tamp, &node_id, rgb_color, alias, - &addresses)); + &addresses, + na_tlvs)); assert(node_id_eq(&node_id, n)); } diff --git a/devtools/create-gossipstore.c b/devtools/create-gossipstore.c index 42c9db3958e1..8fde975a59df 100644 --- a/devtools/create-gossipstore.c +++ b/devtools/create-gossipstore.c @@ -88,9 +88,12 @@ static u32 get_node_announce_timestamp(const u8 *msg) struct node_id id; u8 rgb_color[3], alias[32]; u8 *features, *addresses; + struct tlv_node_ann_tlvs *na_tlvs; + na_tlvs = tlv_node_ann_tlvs_new(tmpctx); if (fromwire_node_announcement(tmpctx, msg, &sig, &features, ×tamp, - &id, rgb_color, alias, &addresses)) + &id, rgb_color, alias, &addresses, + na_tlvs)) return timestamp; errx(1, "Invalid node_announcement"); diff --git a/devtools/mkgossip.c b/devtools/mkgossip.c index 63d7b51b8127..5e732e483bf3 100644 --- a/devtools/mkgossip.c +++ b/devtools/mkgossip.c @@ -201,14 +201,17 @@ static void print_nannounce(const struct node_id *nodeid, struct sha256_double hash; secp256k1_ecdsa_signature sig; char alias[33]; + struct tlv_node_ann_tlvs *tlvs; u8 *nannounce; memset(&sig, 0, sizeof(sig)); assert(hex_str_size(sizeof(*nodeid)) >= sizeof(alias)); hex_encode(nodeid, hex_data_size(sizeof(alias)), alias, sizeof(alias)); + tlvs = tlv_node_ann_tlvs_new(NULL); nannounce = towire_node_announcement(NULL, &sig, NULL, opts->timestamp, nodeid, nodeid->k, (u8 *)alias, - opts->addresses); + opts->addresses, + tlvs); sha256_double(&hash, nannounce + node_announcement_offset, tal_count(nannounce) - node_announcement_offset); sign_hash(privkey, &hash, &sig); @@ -221,6 +224,22 @@ static void print_nannounce(const struct node_id *nodeid, printf(" rgb_color=%s\n", tal_hexstr(NULL, nodeid->k, 3)); printf(" alias=%s\n", tal_hexstr(NULL, alias, 32)); printf(" addresses=%s\n", tal_hex(NULL, opts->addresses)); + + if (tlvs->option_will_fund) { + struct lease_rates *rates = tlvs->option_will_fund; + printf(" TLV option_will_fund\n"); + printf(" lease_fee_basis=%d\n", + rates->lease_fee_basis); + printf(" lease_fee_base_sat=%d\n", + rates->lease_fee_base_sat); + printf(" funding_weight=%d\n", + rates->funding_weight); + printf(" channel_fee_max_proportional_thousandths=%d\n", + rates->channel_fee_max_proportional_thousandths); + printf(" channel_fee_max_base_msat=%d\n", + rates->channel_fee_max_base_msat); + } + tal_free(tlvs); } int main(int argc, char *argv[]) diff --git a/gossipd/gossip_generation.c b/gossipd/gossip_generation.c index 1baddd1fca37..a0de610844bf 100644 --- a/gossipd/gossip_generation.c +++ b/gossipd/gossip_generation.c @@ -29,6 +29,7 @@ static u8 *create_node_announcement(const tal_t *ctx, struct daemon *daemon, { u8 *addresses = tal_arr(tmpctx, u8, 0); u8 *announcement; + struct tlv_node_ann_tlvs *na_tlv; size_t i; if (!sig) @@ -37,13 +38,15 @@ static u8 *create_node_announcement(const tal_t *ctx, struct daemon *daemon, for (i = 0; i < tal_count(daemon->announcable); i++) towire_wireaddr(&addresses, &daemon->announcable[i]); + na_tlv = tlv_node_ann_tlvs_new(tmpctx); announcement = towire_node_announcement(ctx, sig, daemon->our_features->bits [NODE_ANNOUNCE_FEATURE], timestamp, &daemon->id, daemon->rgb, daemon->alias, - addresses); + addresses, + na_tlv); return announcement; } diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index 5619b5ef7b3d..1030918f4284 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -164,6 +164,7 @@ static bool get_node_announcement(const tal_t *ctx, secp256k1_ecdsa_signature signature; u32 timestamp; u8 *addresses; + struct tlv_node_ann_tlvs *na_tlvs; if (!n->bcast.index) return false; @@ -171,11 +172,13 @@ static bool get_node_announcement(const tal_t *ctx, msg = gossip_store_get(tmpctx, daemon->rstate->gs, n->bcast.index); /* Note: validity of node_id is already checked. */ + na_tlvs = tlv_node_ann_tlvs_new(ctx); if (!fromwire_node_announcement(ctx, msg, &signature, features, ×tamp, &id, rgb_color, alias, - &addresses)) { + &addresses, + na_tlvs)) { status_broken("Bad local node_announcement @%u: %s", n->bcast.index, tal_hex(tmpctx, msg)); return false; @@ -728,6 +731,7 @@ static struct io_plan *peer_msg_in(struct io_conn *conn, case WIRE_COMMITMENT_SIGNED: case WIRE_REVOKE_AND_ACK: case WIRE_UPDATE_FEE: + case WIRE_UPDATE_BLOCKHEIGHT: case WIRE_CHANNEL_REESTABLISH: case WIRE_ANNOUNCEMENT_SIGNATURES: case WIRE_GOSSIP_TIMESTAMP_FILTER: diff --git a/gossipd/routing.c b/gossipd/routing.c index 321ce14ba1cf..ed79c82a8161 100644 --- a/gossipd/routing.c +++ b/gossipd/routing.c @@ -2427,6 +2427,7 @@ bool routing_add_node_announcement(struct routing_state *rstate, u8 rgb_color[3]; u8 alias[32]; u8 *features, *addresses; + struct tlv_node_ann_tlvs *na_tlv; if (was_unknown) *was_unknown = false; @@ -2436,10 +2437,12 @@ bool routing_add_node_announcement(struct routing_state *rstate, tal_steal(tmpctx, msg); /* Note: validity of node_id is already checked. */ + na_tlv = tlv_node_ann_tlvs_new(tmpctx); if (!fromwire_node_announcement(tmpctx, msg, &signature, &features, ×tamp, &node_id, rgb_color, alias, - &addresses)) { + &addresses, + na_tlv)) { return false; } @@ -2572,15 +2575,18 @@ u8 *handle_node_announcement(struct routing_state *rstate, const u8 *node_ann, u8 *features, *addresses; struct wireaddr *wireaddrs; size_t len = tal_count(node_ann); + struct tlv_node_ann_tlvs *na_tlv; if (was_unknown) *was_unknown = false; serialized = tal_dup_arr(tmpctx, u8, node_ann, len, 0); + na_tlv = tlv_node_ann_tlvs_new(tmpctx); if (!fromwire_node_announcement(tmpctx, serialized, &signature, &features, ×tamp, &node_id, rgb_color, alias, - &addresses)) { + &addresses, + na_tlv)) { /* BOLT #7: * * - if `node_id` is NOT a valid compressed public key: diff --git a/openingd/dualopend.c b/openingd/dualopend.c index ed5f58300198..7d8dadbb589f 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -1252,6 +1252,7 @@ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state) case WIRE_COMMITMENT_SIGNED: case WIRE_REVOKE_AND_ACK: case WIRE_UPDATE_FEE: + case WIRE_UPDATE_BLOCKHEIGHT: case WIRE_CHANNEL_REESTABLISH: case WIRE_ANNOUNCEMENT_SIGNATURES: case WIRE_GOSSIP_TIMESTAMP_FILTER: @@ -1599,6 +1600,7 @@ static bool run_tx_interactive(struct state *state, case WIRE_COMMITMENT_SIGNED: case WIRE_REVOKE_AND_ACK: case WIRE_UPDATE_FEE: + case WIRE_UPDATE_BLOCKHEIGHT: case WIRE_CHANNEL_REESTABLISH: case WIRE_ANNOUNCEMENT_SIGNATURES: case WIRE_GOSSIP_TIMESTAMP_FILTER: @@ -3380,6 +3382,7 @@ static u8 *handle_peer_in(struct state *state) case WIRE_COMMITMENT_SIGNED: case WIRE_REVOKE_AND_ACK: case WIRE_UPDATE_FEE: + case WIRE_UPDATE_BLOCKHEIGHT: case WIRE_CHANNEL_REESTABLISH: case WIRE_ANNOUNCEMENT_SIGNATURES: case WIRE_GOSSIP_TIMESTAMP_FILTER: diff --git a/wire/extracted_peer_04_opt_will_fund.patch b/wire/extracted_peer_04_opt_will_fund.patch new file mode 100644 index 000000000000..c8c279161a23 --- /dev/null +++ b/wire/extracted_peer_04_opt_will_fund.patch @@ -0,0 +1,48 @@ +--- wire/peer_wire.csv 2021-06-10 12:47:17.225844741 -0500 ++++ - 2021-06-10 12:47:40.960373156 -0500 +@@ -143,6 +139,9 @@ + tlvtype,opening_tlvs,option_upfront_shutdown_script,1 + tlvdata,opening_tlvs,option_upfront_shutdown_script,shutdown_len,u16, + tlvdata,opening_tlvs,option_upfront_shutdown_script,shutdown_scriptpubkey,byte,shutdown_len ++tlvtype,opening_tlvs,request_funds,3 ++tlvdata,opening_tlvs,request_funds,requested_sats,u64, ++tlvdata,opening_tlvs,request_funds,blockheight,u32, + msgtype,accept_channel2,65 + msgdata,accept_channel2,channel_id,channel_id, + msgdata,accept_channel2,funding_satoshis,u64, +@@ -162,6 +161,15 @@ + tlvtype,accept_tlvs,option_upfront_shutdown_script,1 + tlvdata,accept_tlvs,option_upfront_shutdown_script,shutdown_len,u16, + tlvdata,accept_tlvs,option_upfront_shutdown_script,shutdown_scriptpubkey,byte,shutdown_len ++tlvtype,accept_tlvs,will_fund,2 ++tlvdata,accept_tlvs,will_fund,signature,signature, ++tlvdata,accept_tlvs,will_fund,lease_rates,lease_rates, ++subtype,lease_rates ++subtypedata,lease_rates,channel_fee_max_base_msat,u32, ++subtypedata,lease_rates,channel_fee_max_proportional_thousandths,u16, ++subtypedata,lease_rates,funding_weight,u16, ++subtypedata,lease_rates,lease_fee_base_sat,u32, ++subtypedata,lease_rates,lease_fee_basis,tu32, + msgtype,init_rbf,72 + msgdata,init_rbf,channel_id,channel_id, + msgdata,init_rbf,funding_satoshis,u64, +@@ -215,6 +219,9 @@ + msgtype,update_fee,134 + msgdata,update_fee,channel_id,channel_id, + msgdata,update_fee,feerate_per_kw,u32, ++msgtype,update_blockheight,137 ++msgdata,update_blockheight,channel_id,channel_id, ++msgdata,update_blockheight,blockheight,u32, + msgtype,channel_reestablish,136 + msgdata,channel_reestablish,channel_id,channel_id, + msgdata,channel_reestablish,next_commitment_number,u64, +@@ -249,6 +256,9 @@ + msgdata,node_announcement,alias,byte,32 + msgdata,node_announcement,addrlen,u16, + msgdata,node_announcement,addresses,byte,addrlen ++msgdata,node_announcement,tlvs,node_ann_tlvs, ++tlvtype,node_ann_tlvs,option_will_fund,1 ++tlvdata,node_ann_tlvs,option_will_fund,lease_rates,lease_rates, + msgtype,channel_update,258 + msgdata,channel_update,signature,signature, + msgdata,channel_update,chain_hash,chain_hash, diff --git a/wire/peer_printgen.c b/wire/peer_printgen.c index b2ae43f11b83..73fe3a7d6efc 100644 --- a/wire/peer_printgen.c +++ b/wire/peer_printgen.c @@ -128,6 +128,10 @@ void printpeer_wire_message(const u8 *msg) printf("WIRE_UPDATE_FEE:\n"); printwire_update_fee("update_fee", msg); return; + case WIRE_UPDATE_BLOCKHEIGHT: + printf("WIRE_UPDATE_BLOCKHEIGHT:\n"); + printwire_update_blockheight("update_blockheight", msg); + return; case WIRE_CHANNEL_REESTABLISH: printf("WIRE_CHANNEL_REESTABLISH:\n"); printwire_channel_reestablish("channel_reestablish", msg); @@ -196,6 +200,52 @@ void printwire_witness_element(const char *fieldname, const u8 **cursor, size_t } +void printwire_lease_rates(const char *fieldname, const u8 **cursor, size_t *plen) +{ + + printf("funding_weight="); + u16 funding_weight = fromwire_u16(cursor, plen); + + printwire_u16(tal_fmt(NULL, "%s.funding_weight", fieldname), &funding_weight); + if (!*cursor) { + printf("**TRUNCATED**\n"); + return; + } + printf("lease_fee_basis="); + u16 lease_fee_basis = fromwire_u16(cursor, plen); + + printwire_u16(tal_fmt(NULL, "%s.lease_fee_basis", fieldname), &lease_fee_basis); + if (!*cursor) { + printf("**TRUNCATED**\n"); + return; + } + printf("channel_fee_max_proportional_thousandths="); + u16 channel_fee_max_proportional_thousandths = fromwire_u16(cursor, plen); + + printwire_u16(tal_fmt(NULL, "%s.channel_fee_max_proportional_thousandths", fieldname), &channel_fee_max_proportional_thousandths); + if (!*cursor) { + printf("**TRUNCATED**\n"); + return; + } + printf("lease_fee_base_sat="); + u32 lease_fee_base_sat = fromwire_u32(cursor, plen); + + printwire_u32(tal_fmt(NULL, "%s.lease_fee_base_sat", fieldname), &lease_fee_base_sat); + if (!*cursor) { + printf("**TRUNCATED**\n"); + return; + } + printf("channel_fee_max_base_msat="); + u32 channel_fee_max_base_msat = fromwire_tu32(cursor, plen); + + printwire_u32(tal_fmt(NULL, "%s.channel_fee_max_base_msat", fieldname), &channel_fee_max_base_msat); + if (!*cursor) { + printf("**TRUNCATED**\n"); + return; + } + +} + void printwire_channel_update_checksums(const char *fieldname, const u8 **cursor, size_t *plen) { @@ -461,10 +511,33 @@ static void printwire_tlv_opening_tlvs_option_upfront_shutdown_script(const char return; } +} +static void printwire_tlv_opening_tlvs_request_funds(const char *fieldname, const u8 **cursor, size_t *plen) +{ + printf("(msg_name=%s)\n", "request_funds"); + + printf("requested_sats="); + u64 requested_sats = fromwire_u64(cursor, plen); + + printwire_u64(tal_fmt(NULL, "%s.requested_sats", fieldname), &requested_sats); + if (!*cursor) { + printf("**TRUNCATED**\n"); + return; + } + printf("blockheight="); + u32 blockheight = fromwire_u32(cursor, plen); + + printwire_u32(tal_fmt(NULL, "%s.blockheight", fieldname), &blockheight); + if (!*cursor) { + printf("**TRUNCATED**\n"); + return; + } + } static const struct tlv_print_record_type print_tlvs_opening_tlvs[] = { { 1, printwire_tlv_opening_tlvs_option_upfront_shutdown_script }, + { 3, printwire_tlv_opening_tlvs_request_funds }, }; static void printwire_tlv_accept_tlvs_option_upfront_shutdown_script(const char *fieldname, const u8 **cursor, size_t *plen) @@ -484,10 +557,30 @@ static void printwire_tlv_accept_tlvs_option_upfront_shutdown_script(const char return; } +} +static void printwire_tlv_accept_tlvs_will_fund(const char *fieldname, const u8 **cursor, size_t *plen) +{ + printf("(msg_name=%s)\n", "will_fund"); + + printf("signature="); + secp256k1_ecdsa_signature signature; + fromwire_secp256k1_ecdsa_signature(cursor, plen, &signature); + + printwire_secp256k1_ecdsa_signature(tal_fmt(NULL, "%s.signature", fieldname), &signature); + if (!*cursor) { + printf("**TRUNCATED**\n"); + return; + } + printf("lease_rates="); + printf("{\n"); + printwire_lease_rates(tal_fmt(NULL, "%s.lease_rates", fieldname), cursor, plen); + printf("}\n"); + } static const struct tlv_print_record_type print_tlvs_accept_tlvs[] = { { 1, printwire_tlv_accept_tlvs_option_upfront_shutdown_script }, + { 2, printwire_tlv_accept_tlvs_will_fund }, }; static void printwire_tlv_shutdown_tlvs_wrong_funding(const char *fieldname, const u8 **cursor, size_t *plen) @@ -518,6 +611,21 @@ static const struct tlv_print_record_type print_tlvs_shutdown_tlvs[] = { { 100, printwire_tlv_shutdown_tlvs_wrong_funding }, }; +static void printwire_tlv_node_ann_tlvs_option_will_fund(const char *fieldname, const u8 **cursor, size_t *plen) +{ + printf("(msg_name=%s)\n", "option_will_fund"); + + printf("lease_rates="); + printf("{\n"); + printwire_lease_rates(tal_fmt(NULL, "%s.lease_rates", fieldname), cursor, plen); + printf("}\n"); + +} + +static const struct tlv_print_record_type print_tlvs_node_ann_tlvs[] = { + { 1, printwire_tlv_node_ann_tlvs_option_will_fund }, +}; + static void printwire_tlv_query_short_channel_ids_tlvs_query_flags(const char *fieldname, const u8 **cursor, size_t *plen) { printf("(msg_name=%s)\n", "query_flags"); @@ -2246,6 +2354,37 @@ void printwire_update_fee(const char *fieldname, const u8 *cursor) } + if (plen != 0) + printf("EXTRA: %s\n", tal_hexstr(NULL, cursor, plen)); +} +void printwire_update_blockheight(const char *fieldname, const u8 *cursor) +{ + + size_t plen = tal_count(cursor); + if (fromwire_u16(&cursor, &plen) != WIRE_UPDATE_BLOCKHEIGHT) { + printf("WRONG TYPE?!\n"); + return; + } + + printf("channel_id="); + struct channel_id channel_id; + fromwire_channel_id(&cursor, &plen, &channel_id); + + printwire_channel_id(tal_fmt(NULL, "%s.channel_id", fieldname), &channel_id); + if (!cursor) { + printf("**TRUNCATED**\n"); + return; + } + printf("blockheight="); + u32 blockheight = fromwire_u32(&cursor, &plen); + + printwire_u32(tal_fmt(NULL, "%s.blockheight", fieldname), &blockheight); + if (!cursor) { + printf("**TRUNCATED**\n"); + return; + } + + if (plen != 0) printf("EXTRA: %s\n", tal_hexstr(NULL, cursor, plen)); } @@ -2545,6 +2684,8 @@ void printwire_node_announcement(const char *fieldname, const u8 *cursor) printf("**TRUNCATED**\n"); return; } + printf("tlvs="); + printwire_tlvs(tal_fmt(NULL, "%s.tlvs", fieldname), &cursor, &plen, print_tlvs_node_ann_tlvs, ARRAY_SIZE(print_tlvs_node_ann_tlvs)); if (plen != 0) @@ -2922,6 +3063,9 @@ void printpeer_wire_tlv_message(const char *tlv_name, const u8 *msg) { if (strcmp(tlv_name, "shutdown_tlvs") == 0) { printwire_tlvs(tlv_name, &msg, &plen, print_tlvs_shutdown_tlvs, ARRAY_SIZE(print_tlvs_shutdown_tlvs)); } + if (strcmp(tlv_name, "node_ann_tlvs") == 0) { + printwire_tlvs(tlv_name, &msg, &plen, print_tlvs_node_ann_tlvs, ARRAY_SIZE(print_tlvs_node_ann_tlvs)); + } if (strcmp(tlv_name, "query_short_channel_ids_tlvs") == 0) { printwire_tlvs(tlv_name, &msg, &plen, print_tlvs_query_short_channel_ids_tlvs, ARRAY_SIZE(print_tlvs_query_short_channel_ids_tlvs)); } @@ -2935,4 +3079,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:3ecafff6be37e4049f121dcd6816aada2818fc7c02099372d1358d1b5b9da1ca +// SHA256STAMP:df85cfbd9424cced7ea68df1088da25cfdf548a856c0a189677b4a52428c1914 diff --git a/wire/peer_printgen.h b/wire/peer_printgen.h index 7e494852b018..a0e81f0009e9 100644 --- a/wire/peer_printgen.h +++ b/wire/peer_printgen.h @@ -68,6 +68,8 @@ void printwire_revoke_and_ack(const char *fieldname, const u8 *cursor); void printwire_update_fee(const char *fieldname, const u8 *cursor); +void printwire_update_blockheight(const char *fieldname, const u8 *cursor); + void printwire_channel_reestablish(const char *fieldname, const u8 *cursor); void printwire_announcement_signatures(const char *fieldname, const u8 *cursor); @@ -92,8 +94,9 @@ void printwire_onion_message(const char *fieldname, const u8 *cursor); void printwire_witness_element(const char *fieldname, const u8 **cursor, size_t *plen); +void printwire_lease_rates(const char *fieldname, const u8 **cursor, size_t *plen); void printwire_channel_update_checksums(const char *fieldname, const u8 **cursor, size_t *plen); void printwire_channel_update_timestamps(const char *fieldname, const u8 **cursor, size_t *plen); void printwire_witness_stack(const char *fieldname, const u8 **cursor, size_t *plen); #endif /* LIGHTNING_WIRE_PEER_PRINTGEN_H */ -// SHA256STAMP:3ecafff6be37e4049f121dcd6816aada2818fc7c02099372d1358d1b5b9da1ca +// SHA256STAMP:df85cfbd9424cced7ea68df1088da25cfdf548a856c0a189677b4a52428c1914 diff --git a/wire/peer_wire.c b/wire/peer_wire.c index afc60a2203bb..21a6f6e52d6d 100644 --- a/wire/peer_wire.c +++ b/wire/peer_wire.c @@ -21,6 +21,7 @@ static bool unknown_type(enum peer_wire t) case WIRE_COMMITMENT_SIGNED: case WIRE_REVOKE_AND_ACK: case WIRE_UPDATE_FEE: + case WIRE_UPDATE_BLOCKHEIGHT: case WIRE_CHANNEL_REESTABLISH: case WIRE_ANNOUNCEMENT_SIGNATURES: case WIRE_CHANNEL_ANNOUNCEMENT: @@ -83,6 +84,7 @@ bool is_msg_for_gossipd(const u8 *cursor) case WIRE_COMMITMENT_SIGNED: case WIRE_REVOKE_AND_ACK: case WIRE_UPDATE_FEE: + case WIRE_UPDATE_BLOCKHEIGHT: case WIRE_CHANNEL_REESTABLISH: case WIRE_ANNOUNCEMENT_SIGNATURES: case WIRE_GOSSIP_TIMESTAMP_FILTER: diff --git a/wire/peer_wire.csv b/wire/peer_wire.csv index 40b78f1751c4..7e0777f1be93 100644 --- a/wire/peer_wire.csv +++ b/wire/peer_wire.csv @@ -143,6 +143,9 @@ msgdata,open_channel2,tlvs,opening_tlvs, tlvtype,opening_tlvs,option_upfront_shutdown_script,1 tlvdata,opening_tlvs,option_upfront_shutdown_script,shutdown_len,u16, tlvdata,opening_tlvs,option_upfront_shutdown_script,shutdown_scriptpubkey,byte,shutdown_len +tlvtype,opening_tlvs,request_funds,3 +tlvdata,opening_tlvs,request_funds,requested_sats,u64, +tlvdata,opening_tlvs,request_funds,blockheight,u32, msgtype,accept_channel2,65 msgdata,accept_channel2,channel_id,channel_id, msgdata,accept_channel2,funding_satoshis,u64, @@ -162,6 +165,15 @@ msgdata,accept_channel2,tlvs,accept_tlvs, tlvtype,accept_tlvs,option_upfront_shutdown_script,1 tlvdata,accept_tlvs,option_upfront_shutdown_script,shutdown_len,u16, tlvdata,accept_tlvs,option_upfront_shutdown_script,shutdown_scriptpubkey,byte,shutdown_len +tlvtype,accept_tlvs,will_fund,2 +tlvdata,accept_tlvs,will_fund,signature,signature, +tlvdata,accept_tlvs,will_fund,lease_rates,lease_rates, +subtype,lease_rates +subtypedata,lease_rates,funding_weight,u16, +subtypedata,lease_rates,lease_fee_basis,u16, +subtypedata,lease_rates,channel_fee_max_proportional_thousandths,u16, +subtypedata,lease_rates,lease_fee_base_sat,u32, +subtypedata,lease_rates,channel_fee_max_base_msat,tu32, msgtype,init_rbf,72 msgdata,init_rbf,channel_id,channel_id, msgdata,init_rbf,funding_satoshis,u64, @@ -215,6 +227,9 @@ msgdata,revoke_and_ack,next_per_commitment_point,point, msgtype,update_fee,134 msgdata,update_fee,channel_id,channel_id, msgdata,update_fee,feerate_per_kw,u32, +msgtype,update_blockheight,137 +msgdata,update_blockheight,channel_id,channel_id, +msgdata,update_blockheight,blockheight,u32, msgtype,channel_reestablish,136 msgdata,channel_reestablish,channel_id,channel_id, msgdata,channel_reestablish,next_commitment_number,u64, @@ -249,6 +264,9 @@ msgdata,node_announcement,rgb_color,byte,3 msgdata,node_announcement,alias,byte,32 msgdata,node_announcement,addrlen,u16, msgdata,node_announcement,addresses,byte,addrlen +msgdata,node_announcement,tlvs,node_ann_tlvs, +tlvtype,node_ann_tlvs,option_will_fund,1 +tlvdata,node_ann_tlvs,option_will_fund,lease_rates,lease_rates, msgtype,channel_update,258 msgdata,channel_update,signature,signature, msgdata,channel_update,chain_hash,chain_hash, diff --git a/wire/peer_wiregen.c b/wire/peer_wiregen.c index d025048e5afb..2c03846c86ed 100644 --- a/wire/peer_wiregen.c +++ b/wire/peer_wiregen.c @@ -49,6 +49,7 @@ const char *peer_wire_name(int e) case WIRE_COMMITMENT_SIGNED: return "WIRE_COMMITMENT_SIGNED"; case WIRE_REVOKE_AND_ACK: return "WIRE_REVOKE_AND_ACK"; case WIRE_UPDATE_FEE: return "WIRE_UPDATE_FEE"; + case WIRE_UPDATE_BLOCKHEIGHT: return "WIRE_UPDATE_BLOCKHEIGHT"; case WIRE_CHANNEL_REESTABLISH: return "WIRE_CHANNEL_REESTABLISH"; case WIRE_ANNOUNCEMENT_SIGNATURES: return "WIRE_ANNOUNCEMENT_SIGNATURES"; case WIRE_CHANNEL_ANNOUNCEMENT: return "WIRE_CHANNEL_ANNOUNCEMENT"; @@ -98,6 +99,7 @@ bool peer_wire_is_defined(u16 type) case WIRE_COMMITMENT_SIGNED:; case WIRE_REVOKE_AND_ACK:; case WIRE_UPDATE_FEE:; + case WIRE_UPDATE_BLOCKHEIGHT:; case WIRE_CHANNEL_REESTABLISH:; case WIRE_ANNOUNCEMENT_SIGNATURES:; case WIRE_CHANNEL_ANNOUNCEMENT:; @@ -138,6 +140,26 @@ fromwire_u8_array(cursor, plen, witness_element->witness, len); return witness_element; } +/* SUBTYPE: LEASE_RATES */ +void towire_lease_rates(u8 **p, const struct lease_rates *lease_rates) +{ + + towire_u16(p, lease_rates->funding_weight); + towire_u16(p, lease_rates->lease_fee_basis); + towire_u16(p, lease_rates->channel_fee_max_proportional_thousandths); + towire_u32(p, lease_rates->lease_fee_base_sat); + towire_tu32(p, lease_rates->channel_fee_max_base_msat); +} +void fromwire_lease_rates(const u8 **cursor, size_t *plen, struct lease_rates *lease_rates) +{ + + lease_rates->funding_weight = fromwire_u16(cursor, plen); + lease_rates->lease_fee_basis = fromwire_u16(cursor, plen); + lease_rates->channel_fee_max_proportional_thousandths = fromwire_u16(cursor, plen); + lease_rates->lease_fee_base_sat = fromwire_u32(cursor, plen); + lease_rates->channel_fee_max_base_msat = fromwire_tu32(cursor, plen); +} + /* SUBTYPE: CHANNEL_UPDATE_CHECKSUMS */ void towire_channel_update_checksums(u8 **p, const struct channel_update_checksums *channel_update_checksums) { @@ -609,20 +631,46 @@ static void fromwire_tlv_opening_tlvs_option_upfront_shutdown_script(const u8 ** r->option_upfront_shutdown_script->shutdown_scriptpubkey = shutdown_len ? tal_arr(r->option_upfront_shutdown_script, u8, shutdown_len) : NULL; fromwire_u8_array(cursor, plen, r->option_upfront_shutdown_script->shutdown_scriptpubkey, shutdown_len); } +/* OPENING_TLVS MSG: request_funds */ +static u8 *towire_tlv_opening_tlvs_request_funds(const tal_t *ctx, const void *vrecord) +{ + const struct tlv_opening_tlvs *r = vrecord; + u8 *ptr; + + if (!r->request_funds) + return NULL; + + + ptr = tal_arr(ctx, u8, 0); + + towire_u64(&ptr, r->request_funds->requested_sats); + + towire_u32(&ptr, r->request_funds->blockheight); + return ptr; +} +static void fromwire_tlv_opening_tlvs_request_funds(const u8 **cursor, size_t *plen, void *vrecord) +{ + struct tlv_opening_tlvs *r = vrecord; + + r->request_funds = tal(r, struct tlv_opening_tlvs_request_funds); + r->request_funds->requested_sats = fromwire_u64(cursor, plen); + r->request_funds->blockheight = fromwire_u32(cursor, plen); +} static const struct tlv_record_type tlvs_opening_tlvs[] = { { 1, towire_tlv_opening_tlvs_option_upfront_shutdown_script, fromwire_tlv_opening_tlvs_option_upfront_shutdown_script }, + { 3, towire_tlv_opening_tlvs_request_funds, fromwire_tlv_opening_tlvs_request_funds }, }; void towire_opening_tlvs(u8 **pptr, const struct tlv_opening_tlvs *record) { - towire_tlv(pptr, tlvs_opening_tlvs, 1, record); + towire_tlv(pptr, tlvs_opening_tlvs, 2, record); } bool fromwire_opening_tlvs(const u8 **cursor, size_t *max, struct tlv_opening_tlvs *record) { - return fromwire_tlv(cursor, max, tlvs_opening_tlvs, 1, record, &record->fields); + return fromwire_tlv(cursor, max, tlvs_opening_tlvs, 2, record, &record->fields); } bool opening_tlvs_is_valid(const struct tlv_opening_tlvs *record, size_t *err_index) @@ -669,20 +717,46 @@ static void fromwire_tlv_accept_tlvs_option_upfront_shutdown_script(const u8 **c r->option_upfront_shutdown_script->shutdown_scriptpubkey = shutdown_len ? tal_arr(r->option_upfront_shutdown_script, u8, shutdown_len) : NULL; fromwire_u8_array(cursor, plen, r->option_upfront_shutdown_script->shutdown_scriptpubkey, shutdown_len); } +/* ACCEPT_TLVS MSG: will_fund */ +static u8 *towire_tlv_accept_tlvs_will_fund(const tal_t *ctx, const void *vrecord) +{ + const struct tlv_accept_tlvs *r = vrecord; + u8 *ptr; + + if (!r->will_fund) + return NULL; + + + ptr = tal_arr(ctx, u8, 0); + + towire_secp256k1_ecdsa_signature(&ptr, &r->will_fund->signature); + + towire_lease_rates(&ptr, &r->will_fund->lease_rates); + return ptr; +} +static void fromwire_tlv_accept_tlvs_will_fund(const u8 **cursor, size_t *plen, void *vrecord) +{ + struct tlv_accept_tlvs *r = vrecord; + + r->will_fund = tal(r, struct tlv_accept_tlvs_will_fund); + fromwire_secp256k1_ecdsa_signature(cursor, plen, &r->will_fund->signature); + fromwire_lease_rates(cursor, plen, &r->will_fund->lease_rates); +} static const struct tlv_record_type tlvs_accept_tlvs[] = { { 1, towire_tlv_accept_tlvs_option_upfront_shutdown_script, fromwire_tlv_accept_tlvs_option_upfront_shutdown_script }, + { 2, towire_tlv_accept_tlvs_will_fund, fromwire_tlv_accept_tlvs_will_fund }, }; void towire_accept_tlvs(u8 **pptr, const struct tlv_accept_tlvs *record) { - towire_tlv(pptr, tlvs_accept_tlvs, 1, record); + towire_tlv(pptr, tlvs_accept_tlvs, 2, record); } bool fromwire_accept_tlvs(const u8 **cursor, size_t *max, struct tlv_accept_tlvs *record) { - return fromwire_tlv(cursor, max, tlvs_accept_tlvs, 1, record, &record->fields); + return fromwire_tlv(cursor, max, tlvs_accept_tlvs, 2, record, &record->fields); } bool accept_tlvs_is_valid(const struct tlv_accept_tlvs *record, size_t *err_index) @@ -748,6 +822,61 @@ bool shutdown_tlvs_is_valid(const struct tlv_shutdown_tlvs *record, size_t *err_ } +struct tlv_node_ann_tlvs *tlv_node_ann_tlvs_new(const tal_t *ctx) +{ + /* Initialize everything to NULL. (Quiet, C pedants!) */ + struct tlv_node_ann_tlvs *inst = talz(ctx, struct tlv_node_ann_tlvs); + + /* Initialized the fields to an empty array. */ + inst->fields = tal_arr(inst, struct tlv_field, 0); + return inst; +} + +/* NODE_ANN_TLVS MSG: option_will_fund */ +static u8 *towire_tlv_node_ann_tlvs_option_will_fund(const tal_t *ctx, const void *vrecord) +{ + const struct tlv_node_ann_tlvs *r = vrecord; + u8 *ptr; + + if (!r->option_will_fund) + return NULL; + + + ptr = tal_arr(ctx, u8, 0); + + towire_lease_rates(&ptr, r->option_will_fund); + return ptr; +} +static void fromwire_tlv_node_ann_tlvs_option_will_fund(const u8 **cursor, size_t *plen, void *vrecord) +{ + struct tlv_node_ann_tlvs *r = vrecord; + + r->option_will_fund = tal(r, struct lease_rates); + +fromwire_lease_rates(cursor, plen, &*r->option_will_fund); +} + +static const struct tlv_record_type tlvs_node_ann_tlvs[] = { + { 1, towire_tlv_node_ann_tlvs_option_will_fund, fromwire_tlv_node_ann_tlvs_option_will_fund }, +}; + +void towire_node_ann_tlvs(u8 **pptr, const struct tlv_node_ann_tlvs *record) +{ + towire_tlv(pptr, tlvs_node_ann_tlvs, 1, record); +} + + +bool fromwire_node_ann_tlvs(const u8 **cursor, size_t *max, struct tlv_node_ann_tlvs *record) +{ + return fromwire_tlv(cursor, max, tlvs_node_ann_tlvs, 1, record, &record->fields); +} + +bool node_ann_tlvs_is_valid(const struct tlv_node_ann_tlvs *record, size_t *err_index) +{ + return tlv_fields_valid(record->fields, err_index); +} + + struct tlv_query_short_channel_ids_tlvs *tlv_query_short_channel_ids_tlvs_new(const tal_t *ctx) { /* Initialize everything to NULL. (Quiet, C pedants!) */ @@ -1926,6 +2055,29 @@ bool fromwire_update_fee(const void *p, struct channel_id *channel_id, u32 *feer return cursor != NULL; } +/* WIRE: UPDATE_BLOCKHEIGHT */ +u8 *towire_update_blockheight(const tal_t *ctx, const struct channel_id *channel_id, u32 blockheight) +{ + u8 *p = tal_arr(ctx, u8, 0); + + towire_u16(&p, WIRE_UPDATE_BLOCKHEIGHT); + towire_channel_id(&p, channel_id); + towire_u32(&p, blockheight); + + return memcheck(p, tal_count(p)); +} +bool fromwire_update_blockheight(const void *p, struct channel_id *channel_id, u32 *blockheight) +{ + const u8 *cursor = p; + size_t plen = tal_count(p); + + if (fromwire_u16(&cursor, &plen) != WIRE_UPDATE_BLOCKHEIGHT) + return false; + fromwire_channel_id(&cursor, &plen, channel_id); + *blockheight = fromwire_u32(&cursor, &plen); + return cursor != NULL; +} + /* WIRE: CHANNEL_REESTABLISH */ u8 *towire_channel_reestablish(const tal_t *ctx, const struct channel_id *channel_id, u64 next_commitment_number, u64 next_revocation_number, const struct secret *your_last_per_commitment_secret, const struct pubkey *my_current_per_commitment_point) { @@ -2031,7 +2183,7 @@ bool fromwire_channel_announcement(const tal_t *ctx, const void *p, secp256k1_ec } /* WIRE: NODE_ANNOUNCEMENT */ -u8 *towire_node_announcement(const tal_t *ctx, const secp256k1_ecdsa_signature *signature, const u8 *features, u32 timestamp, const struct node_id *node_id, const u8 rgb_color[3], const u8 alias[32], const u8 *addresses) +u8 *towire_node_announcement(const tal_t *ctx, const secp256k1_ecdsa_signature *signature, const u8 *features, u32 timestamp, const struct node_id *node_id, const u8 rgb_color[3], const u8 alias[32], const u8 *addresses, const struct tlv_node_ann_tlvs *tlvs) { u16 flen = tal_count(features); u16 addrlen = tal_count(addresses); @@ -2047,10 +2199,11 @@ u8 *towire_node_announcement(const tal_t *ctx, const secp256k1_ecdsa_signature * towire_u8_array(&p, alias, 32); towire_u16(&p, addrlen); towire_u8_array(&p, addresses, addrlen); + towire_node_ann_tlvs(&p, tlvs); return memcheck(p, tal_count(p)); } -bool fromwire_node_announcement(const tal_t *ctx, const void *p, secp256k1_ecdsa_signature *signature, u8 **features, u32 *timestamp, struct node_id *node_id, u8 rgb_color[3], u8 alias[32], u8 **addresses) +bool fromwire_node_announcement(const tal_t *ctx, const void *p, secp256k1_ecdsa_signature *signature, u8 **features, u32 *timestamp, struct node_id *node_id, u8 rgb_color[3], u8 alias[32], u8 **addresses, struct tlv_node_ann_tlvs *tlvs) { u16 flen; u16 addrlen; @@ -2073,6 +2226,7 @@ bool fromwire_node_announcement(const tal_t *ctx, const void *p, secp256k1_ecdsa // 2nd case addresses *addresses = addrlen ? tal_arr(ctx, u8, addrlen) : NULL; fromwire_u8_array(&cursor, &plen, *addresses, addrlen); + fromwire_node_ann_tlvs(&cursor, &plen, tlvs); return cursor != NULL; } @@ -2330,4 +2484,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:3ecafff6be37e4049f121dcd6816aada2818fc7c02099372d1358d1b5b9da1ca +// SHA256STAMP:df85cfbd9424cced7ea68df1088da25cfdf548a856c0a189677b4a52428c1914 diff --git a/wire/peer_wiregen.h b/wire/peer_wiregen.h index f4b5b7722b43..0b764169dcf0 100644 --- a/wire/peer_wiregen.h +++ b/wire/peer_wiregen.h @@ -46,6 +46,7 @@ enum peer_wire { WIRE_COMMITMENT_SIGNED = 132, WIRE_REVOKE_AND_ACK = 133, WIRE_UPDATE_FEE = 134, + WIRE_UPDATE_BLOCKHEIGHT = 137, WIRE_CHANNEL_REESTABLISH = 136, WIRE_ANNOUNCEMENT_SIGNATURES = 259, WIRE_CHANNEL_ANNOUNCEMENT = 256, @@ -73,6 +74,13 @@ bool peer_wire_is_defined(u16 type); struct witness_element { u8 *witness; }; +struct lease_rates { + u16 funding_weight; + u16 lease_fee_basis; + u16 channel_fee_max_proportional_thousandths; + u32 lease_fee_base_sat; + u32 channel_fee_max_base_msat; +}; struct channel_update_checksums { u32 checksum_node_id_1; u32 checksum_node_id_2; @@ -92,9 +100,17 @@ struct tlv_n1_tlv3 { struct tlv_opening_tlvs_option_upfront_shutdown_script { u8 *shutdown_scriptpubkey; }; +struct tlv_opening_tlvs_request_funds { + u64 requested_sats; + u32 blockheight; +}; struct tlv_accept_tlvs_option_upfront_shutdown_script { u8 *shutdown_scriptpubkey; }; +struct tlv_accept_tlvs_will_fund { + secp256k1_ecdsa_signature signature; + struct lease_rates lease_rates; +}; struct tlv_shutdown_tlvs_wrong_funding { struct bitcoin_txid txid; u32 outnum; @@ -158,6 +174,7 @@ struct tlv_opening_tlvs { /* TODO The following explicit fields could just point into the * tlv_field entries above to save on memory. */ struct tlv_opening_tlvs_option_upfront_shutdown_script *option_upfront_shutdown_script; + struct tlv_opening_tlvs_request_funds *request_funds; }; struct tlv_accept_tlvs { /* Raw fields including unknown ones. */ @@ -166,6 +183,7 @@ struct tlv_accept_tlvs { /* TODO The following explicit fields could just point into the * tlv_field entries above to save on memory. */ struct tlv_accept_tlvs_option_upfront_shutdown_script *option_upfront_shutdown_script; + struct tlv_accept_tlvs_will_fund *will_fund; }; struct tlv_shutdown_tlvs { /* Raw fields including unknown ones. */ @@ -175,6 +193,14 @@ struct tlv_shutdown_tlvs { * tlv_field entries above to save on memory. */ struct tlv_shutdown_tlvs_wrong_funding *wrong_funding; }; +struct tlv_node_ann_tlvs { + /* Raw fields including unknown ones. */ + struct tlv_field *fields; + + /* TODO The following explicit fields could just point into the + * tlv_field entries above to save on memory. */ + struct lease_rates *option_will_fund; +}; struct tlv_query_short_channel_ids_tlvs { /* Raw fields including unknown ones. */ struct tlv_field *fields; @@ -529,6 +555,43 @@ void towire_shutdown_tlvs(u8 **pptr, const struct tlv_shutdown_tlvs *record); bool shutdown_tlvs_is_valid(const struct tlv_shutdown_tlvs *record, size_t *err_index); +struct tlv_node_ann_tlvs *tlv_node_ann_tlvs_new(const tal_t *ctx); + +/** + * Deserialize a TLV stream for the node_ann_tlvs namespace. + * + * This function will parse any TLV stream, as long as the type, length and + * value fields are formatted correctly. Fields that are not known in the + * current namespace are stored in the `fields` member. Validity can be + * checked using node_ann_tlvs_is_valid. + */ +bool fromwire_node_ann_tlvs(const u8 **cursor, size_t *max, + struct tlv_node_ann_tlvs * record); + +/** + * Serialize a TLV stream for the node_ann_tlvs namespace. + * + * This function only considers known fields from the node_ann_tlvs namespace, + * and will ignore any fields that may be stored in the `fields` member. This + * ensures that the resulting stream is valid according to + * `node_ann_tlvs_is_valid`. + */ +void towire_node_ann_tlvs(u8 **pptr, const struct tlv_node_ann_tlvs *record); + +/** + * Check that the TLV stream is valid. + * + * Enforces the followin validity rules: + * - Types must be in monotonic non-repeating order + * - We must understand all even types + * + * Returns false if an error was detected, otherwise returns true. If err_index + * is non-null and we detect an error it is set to the index of the first error + * detected. + */ +bool node_ann_tlvs_is_valid(const struct tlv_node_ann_tlvs *record, + size_t *err_index); + struct tlv_query_short_channel_ids_tlvs *tlv_query_short_channel_ids_tlvs_new(const tal_t *ctx); /** @@ -681,6 +744,10 @@ bool onion_message_tlvs_is_valid(const struct tlv_onion_message_tlvs *record, void towire_witness_element(u8 **p, const struct witness_element *witness_element); struct witness_element *fromwire_witness_element(const tal_t *ctx, const u8 **cursor, size_t *plen); +/* SUBTYPE: LEASE_RATES */ +void towire_lease_rates(u8 **p, const struct lease_rates *lease_rates); +void fromwire_lease_rates(const u8 **cursor, size_t *plen, struct lease_rates *lease_rates); + /* SUBTYPE: CHANNEL_UPDATE_CHECKSUMS */ void towire_channel_update_checksums(u8 **p, const struct channel_update_checksums *channel_update_checksums); void fromwire_channel_update_checksums(const u8 **cursor, size_t *plen, struct channel_update_checksums *channel_update_checksums); @@ -809,6 +876,10 @@ bool fromwire_revoke_and_ack(const void *p, struct channel_id *channel_id, struc u8 *towire_update_fee(const tal_t *ctx, const struct channel_id *channel_id, u32 feerate_per_kw); bool fromwire_update_fee(const void *p, struct channel_id *channel_id, u32 *feerate_per_kw); +/* WIRE: UPDATE_BLOCKHEIGHT */ +u8 *towire_update_blockheight(const tal_t *ctx, const struct channel_id *channel_id, u32 blockheight); +bool fromwire_update_blockheight(const void *p, struct channel_id *channel_id, u32 *blockheight); + /* WIRE: CHANNEL_REESTABLISH */ u8 *towire_channel_reestablish(const tal_t *ctx, const struct channel_id *channel_id, u64 next_commitment_number, u64 next_revocation_number, const struct secret *your_last_per_commitment_secret, const struct pubkey *my_current_per_commitment_point); bool fromwire_channel_reestablish(const void *p, struct channel_id *channel_id, u64 *next_commitment_number, u64 *next_revocation_number, struct secret *your_last_per_commitment_secret, struct pubkey *my_current_per_commitment_point); @@ -822,8 +893,8 @@ u8 *towire_channel_announcement(const tal_t *ctx, const secp256k1_ecdsa_signatur bool fromwire_channel_announcement(const tal_t *ctx, const void *p, secp256k1_ecdsa_signature *node_signature_1, secp256k1_ecdsa_signature *node_signature_2, secp256k1_ecdsa_signature *bitcoin_signature_1, secp256k1_ecdsa_signature *bitcoin_signature_2, u8 **features, struct bitcoin_blkid *chain_hash, struct short_channel_id *short_channel_id, struct node_id *node_id_1, struct node_id *node_id_2, struct pubkey *bitcoin_key_1, struct pubkey *bitcoin_key_2); /* WIRE: NODE_ANNOUNCEMENT */ -u8 *towire_node_announcement(const tal_t *ctx, const secp256k1_ecdsa_signature *signature, const u8 *features, u32 timestamp, const struct node_id *node_id, const u8 rgb_color[3], const u8 alias[32], const u8 *addresses); -bool fromwire_node_announcement(const tal_t *ctx, const void *p, secp256k1_ecdsa_signature *signature, u8 **features, u32 *timestamp, struct node_id *node_id, u8 rgb_color[3], u8 alias[32], u8 **addresses); +u8 *towire_node_announcement(const tal_t *ctx, const secp256k1_ecdsa_signature *signature, const u8 *features, u32 timestamp, const struct node_id *node_id, const u8 rgb_color[3], const u8 alias[32], const u8 *addresses, const struct tlv_node_ann_tlvs *tlvs); +bool fromwire_node_announcement(const tal_t *ctx, const void *p, secp256k1_ecdsa_signature *signature, u8 **features, u32 *timestamp, struct node_id *node_id, u8 rgb_color[3], u8 alias[32], u8 **addresses, struct tlv_node_ann_tlvs *tlvs); /* WIRE: CHANNEL_UPDATE */ u8 *towire_channel_update(const tal_t *ctx, const secp256k1_ecdsa_signature *signature, const struct bitcoin_blkid *chain_hash, const struct short_channel_id *short_channel_id, u32 timestamp, u8 message_flags, u8 channel_flags, u16 cltv_expiry_delta, struct amount_msat htlc_minimum_msat, u32 fee_base_msat, u32 fee_proportional_millionths); @@ -859,4 +930,4 @@ bool fromwire_channel_update_option_channel_htlc_max(const void *p, secp256k1_ec #endif /* LIGHTNING_WIRE_PEER_WIREGEN_H */ -// SHA256STAMP:3ecafff6be37e4049f121dcd6816aada2818fc7c02099372d1358d1b5b9da1ca +// SHA256STAMP:df85cfbd9424cced7ea68df1088da25cfdf548a856c0a189677b4a52428c1914 diff --git a/wire/test/run-peer-wire.c b/wire/test/run-peer-wire.c index 160a889bbf35..63cff64940bf 100644 --- a/wire/test/run-peer-wire.c +++ b/wire/test/run-peer-wire.c @@ -167,6 +167,7 @@ struct msg_node_announcement { u8 alias[32]; u8 *features; u8 *addresses; + struct tlv_node_ann_tlvs *tlvs; }; struct msg_open_channel { struct bitcoin_blkid chain_hash; @@ -371,12 +372,14 @@ static void *towire_struct_node_announcement(const tal_t *ctx, &s->node_id, s->rgb_color, s->alias, - s->addresses); + s->addresses, + s->tlvs); } static struct msg_node_announcement *fromwire_struct_node_announcement(const tal_t *ctx, const void *p) { struct msg_node_announcement *s = tal(ctx, struct msg_node_announcement); + s->tlvs = tlv_node_ann_tlvs_new(s); if (!fromwire_node_announcement(s, p, &s->signature, &s->features, @@ -384,7 +387,8 @@ static struct msg_node_announcement *fromwire_struct_node_announcement(const tal &s->node_id, s->rgb_color, s->alias, - &s->addresses)) + &s->addresses, + s->tlvs)) return tal_free(s); return s; } @@ -925,9 +929,40 @@ static bool update_add_htlc_eq(const struct msg_update_add_htlc *a, return eq_with(a, b, onion_routing_packet); } +static bool +lease_rates_eq(const struct lease_rates *a, + const struct lease_rates *b) +{ + return eq_field(a, b, channel_fee_max_base_msat) + && eq_field(a, b, channel_fee_max_proportional_thousandths) + && eq_field(a, b, funding_weight) + && eq_field(a, b, lease_fee_base_sat) + && eq_field(a, b, lease_fee_basis); +} + static bool node_announcement_eq(const struct msg_node_announcement *a, const struct msg_node_announcement *b) { + /* Both or neither */ + if (!a->tlvs != !b->tlvs) { + abort(); + return false; + } + + if (!a->tlvs) + goto body_check; + + /* Both or neither */ + if (!a->tlvs->option_will_fund != !b->tlvs->option_will_fund) { + return false; + } + + if (a->tlvs->option_will_fund + && !lease_rates_eq(a->tlvs->option_will_fund, + b->tlvs->option_will_fund)) + return false; + +body_check: return eq_with(a, b, node_id) && eq_field(a, b, rgb_color) && eq_field(a, b, alias) @@ -1165,11 +1200,15 @@ int main(int argc, char *argv[]) memset(na.features, 2, 2); na.addresses = tal_arr(ctx, u8, 2); memset(na.addresses, 2, 2); + na.tlvs= tlv_node_ann_tlvs_new(ctx); + na.tlvs->option_will_fund = tal(ctx, struct lease_rates); + memset(na.tlvs->option_will_fund, 2, + sizeof(*na.tlvs->option_will_fund)); msg = towire_struct_node_announcement(ctx, &na); na2 = fromwire_struct_node_announcement(ctx, msg); assert(node_announcement_eq(&na, na2)); - test_corruption(&na, na2, node_announcement); + test_corruption_tlv(&na, na2, node_announcement); tal_free(ctx); common_shutdown(); From 23bcfad70e801b63e8bb29340ad8047600b9102d Mon Sep 17 00:00:00 2001 From: niftynei Date: Thu, 27 May 2021 16:35:45 -0500 Subject: [PATCH 02/56] lease_rates: parse them out of node_announcements When we get a node announcement out, we can now pull out its offer characteristic --- gossipd/gossip_generation.c | 13 ++++++++++--- gossipd/gossipd.c | 19 ++++++++++++++----- gossipd/gossipd.h | 4 ++++ lightningd/gossip_msg.c | 15 +++++++++++++++ lightningd/gossip_msg.h | 2 ++ 5 files changed, 45 insertions(+), 8 deletions(-) diff --git a/gossipd/gossip_generation.c b/gossipd/gossip_generation.c index a0de610844bf..25cfcfb19b30 100644 --- a/gossipd/gossip_generation.c +++ b/gossipd/gossip_generation.c @@ -25,7 +25,8 @@ * between the dummy creation and the call with a signature. */ static u8 *create_node_announcement(const tal_t *ctx, struct daemon *daemon, const secp256k1_ecdsa_signature *sig, - u32 timestamp) + u32 timestamp, + const struct lease_rates *rates) { u8 *addresses = tal_arr(tmpctx, u8, 0); u8 *announcement; @@ -39,6 +40,8 @@ static u8 *create_node_announcement(const tal_t *ctx, struct daemon *daemon, towire_wireaddr(&addresses, &daemon->announcable[i]); na_tlv = tlv_node_ann_tlvs_new(tmpctx); + na_tlv->option_will_fund = cast_const(struct lease_rates *, rates); + announcement = towire_node_announcement(ctx, sig, daemon->our_features->bits @@ -164,7 +167,10 @@ static void update_own_node_announcement(struct daemon *daemon) timestamp++; /* Make unsigned announcement. */ - nannounce = create_node_announcement(tmpctx, daemon, NULL, timestamp); + nannounce = create_node_announcement(tmpctx, daemon, NULL, + timestamp, + daemon->rates); + /* If it's the same as the previous, nothing to do. */ if (self && self->bcast.index) { @@ -207,7 +213,8 @@ static void update_own_node_announcement(struct daemon *daemon) /* We got the signature for our provisional node_announcement back * from the HSM, create the real announcement and forward it to * gossipd so it can take care of forwarding it. */ - nannounce = create_node_announcement(NULL, daemon, &sig, timestamp); + nannounce = create_node_announcement(NULL, daemon, &sig, + timestamp, daemon->rates); /* This injects it into the routing code in routing.c; it should not * reject it! */ diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index 1030918f4284..04277d260e08 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -157,7 +157,8 @@ static bool get_node_announcement(const tal_t *ctx, u8 rgb_color[3], u8 alias[32], u8 **features, - struct wireaddr **wireaddrs) + struct wireaddr **wireaddrs, + struct lease_rates **rates) { const u8 *msg; struct node_id id; @@ -197,6 +198,9 @@ static bool get_node_announcement(const tal_t *ctx, } *wireaddrs = read_addresses(ctx, addresses); + + *rates = tal_steal(ctx, na_tlvs->option_will_fund); + tal_free(addresses); return true; } @@ -208,14 +212,15 @@ static bool get_node_announcement_by_id(const tal_t *ctx, u8 rgb_color[3], u8 alias[32], u8 **features, - struct wireaddr **wireaddrs) + struct wireaddr **wireaddrs, + struct lease_rates **rates) { struct node *n = get_node(daemon->rstate, node_id); if (!n) return false; return get_node_announcement(ctx, daemon, n, rgb_color, alias, - features, wireaddrs); + features, wireaddrs, rates); } /*~Routines to handle gossip messages from peer, forwarded by subdaemons. @@ -922,6 +927,7 @@ static struct io_plan *connectd_get_address(struct io_conn *conn, u8 alias[32]; u8 *features; struct wireaddr *addrs; + struct lease_rates *rates; if (!fromwire_gossipd_get_addrs(msg, &id)) { status_broken("Bad gossipd_get_addrs msg from connectd: %s", @@ -930,7 +936,8 @@ static struct io_plan *connectd_get_address(struct io_conn *conn, } if (!get_node_announcement_by_id(tmpctx, daemon, &id, - rgb_color, alias, &features, &addrs)) + rgb_color, alias, &features, &addrs, + &rates)) addrs = NULL; daemon_conn_send(daemon->connectd, @@ -1362,7 +1369,8 @@ static void add_node_entry(const tal_t *ctx, if (get_node_announcement(ctx, daemon, n, e->color, e->alias, &e->features, - &e->addresses)) { + &e->addresses, + &e->rates)) { e->last_timestamp = n->bcast.timestamp; } else { /* Timestamp on wire is an unsigned 32 bit: we use a 64-bit @@ -1918,6 +1926,7 @@ int main(int argc, char *argv[]) daemon->deferred_txouts = tal_arr(daemon, struct short_channel_id, 0); daemon->node_announce_timer = NULL; daemon->current_blockheight = 0; /* i.e. unknown */ + daemon->rates = NULL; /* Tell the ecdh() function how to talk to hsmd */ ecdh_hsmd_setup(HSM_FD, status_failed); diff --git a/gossipd/gossipd.h b/gossipd/gossipd.h index ab01b53aaccc..867c3ef802f9 100644 --- a/gossipd/gossipd.h +++ b/gossipd/gossipd.h @@ -17,6 +17,7 @@ struct chan; struct channel_update_timestamps; struct broadcastable; +struct lease_rates; struct seeker; /*~ The core daemon structure: */ @@ -60,6 +61,9 @@ struct daemon { /* Features lightningd told us to set. */ struct feature_set *our_features; + + /* The channel lease rates we're advertising */ + struct lease_rates *rates; }; struct range_query_reply { diff --git a/lightningd/gossip_msg.c b/lightningd/gossip_msg.c index bc827c938b91..f8e8c0cfb8fb 100644 --- a/lightningd/gossip_msg.c +++ b/lightningd/gossip_msg.c @@ -2,6 +2,7 @@ #include #include #include +#include #include struct gossip_getnodes_entry *fromwire_gossip_getnodes_entry(const tal_t *ctx, @@ -10,6 +11,7 @@ struct gossip_getnodes_entry *fromwire_gossip_getnodes_entry(const tal_t *ctx, u8 numaddresses, i; struct gossip_getnodes_entry *entry; u16 flen; + bool has_rates; entry = tal(ctx, struct gossip_getnodes_entry); fromwire_node_id(pptr, max, &entry->nodeid); @@ -34,6 +36,13 @@ struct gossip_getnodes_entry *fromwire_gossip_getnodes_entry(const tal_t *ctx, fromwire(pptr, max, entry->alias, ARRAY_SIZE(entry->alias)); fromwire(pptr, max, entry->color, ARRAY_SIZE(entry->color)); + has_rates = fromwire_u8(pptr, max); + if (has_rates) { + entry->rates = tal(entry, struct lease_rates); + fromwire_lease_rates(pptr, max, entry->rates); + } else + entry->rates = NULL; + return entry; } @@ -54,6 +63,12 @@ void towire_gossip_getnodes_entry(u8 **pptr, } towire(pptr, entry->alias, ARRAY_SIZE(entry->alias)); towire(pptr, entry->color, ARRAY_SIZE(entry->color)); + + if (entry->rates) { + towire_u8(pptr, 1); + towire_lease_rates(pptr, entry->rates); + } else + towire_u8(pptr, 0); } struct route_hop *fromwire_route_hop(const tal_t *ctx, diff --git a/lightningd/gossip_msg.h b/lightningd/gossip_msg.h index 5f405619212a..58b1e3703871 100644 --- a/lightningd/gossip_msg.h +++ b/lightningd/gossip_msg.h @@ -5,6 +5,7 @@ #include struct route_info; +struct lease_rates; struct gossip_getnodes_entry { struct node_id nodeid; @@ -13,6 +14,7 @@ struct gossip_getnodes_entry { struct wireaddr *addresses; u8 alias[32]; u8 color[3]; + struct lease_rates *rates; }; struct gossip_halfchannel_entry { From e4a4bc6a3661d97de2f03c757a4748054aa8222b Mon Sep 17 00:00:00 2001 From: niftynei Date: Fri, 28 May 2021 15:12:41 -0500 Subject: [PATCH 03/56] gossip/liquidity-ad: node_ann comparison, optional TLV check Correctly mark whether or not the TLV's are the same/different, given two node announcements --- gossipd/gossip_generation.c | 56 +++++-- gossipd/gossip_generation.h | 3 +- gossipd/routing.c | 5 +- gossipd/test/run-bench-find_route.c | 3 +- gossipd/test/run-check_channel_announcement.c | 3 +- gossipd/test/run-check_node_announcement.c | 147 ++++++++++++++++++ gossipd/test/run-find_route-specific.c | 3 +- gossipd/test/run-find_route.c | 3 +- gossipd/test/run-overlong.c | 3 +- gossipd/test/run-txout_failure.c | 3 +- 10 files changed, 210 insertions(+), 19 deletions(-) create mode 100644 gossipd/test/run-check_node_announcement.c diff --git a/gossipd/gossip_generation.c b/gossipd/gossip_generation.c index 25cfcfb19b30..7676cf7c357b 100644 --- a/gossipd/gossip_generation.c +++ b/gossipd/gossip_generation.c @@ -95,13 +95,14 @@ bool cupdate_different(struct gossip_store *gs, || !memeq(oparts[1], osizes[1], nparts[1], nsizes[1]); } -/* Get non-signature, non-timestamp parts of (valid!) node_announcement */ +/* Get non-signature, non-timestamp parts of (valid!) node_announcement, + * with TLV broken out separately */ static void get_nannounce_parts(const u8 *node_announcement, - const u8 *parts[2], - size_t sizes[2]) + const u8 *parts[3], + size_t sizes[3]) { - size_t len; - const u8 *flen; + size_t len, ad_len; + const u8 *flen, *ad_start; /* BOLT #7: * @@ -124,17 +125,43 @@ static void get_nannounce_parts(const u8 *node_announcement, sizes[0] = 2 + fromwire_u16(&flen, &len); assert(flen != NULL && len >= 4); + /* BOLT-0fe3485a5320efaa2be8cfa0e570ad4d0259cec3 #7: + * + * * [`u32`:`timestamp`] + * * [`point`:`node_id`] + * * [`3*byte`:`rgb_color`] + * * [`32*byte`:`alias`] + * * [`u16`:`addrlen`] + * * [`addrlen*byte`:`addresses`] + * * [`node_ann_tlvs`:`tlvs`] + */ parts[1] = node_announcement + 2 + 64 + sizes[0] + 4; - sizes[1] = tal_count(node_announcement) - (2 + 64 + sizes[0] + 4); + + /* Find the end of the addresses */ + ad_start = parts[1] + 33 + 3 + 32; + len = tal_count(node_announcement) + - (2 + 64 + sizes[0] + 4 + 33 + 3 + 32); + ad_len = fromwire_u16(&ad_start, &len); + assert(ad_start != NULL && len >= ad_len); + + sizes[1] = 33 + 3 + 32 + 2 + ad_len; + + /* Is there a TLV ? */ + sizes[2] = len - ad_len; + if (sizes[2] != 0) + parts[2] = parts[1] + sizes[1]; + else + parts[2] = NULL; } /* Is this node_announcement different from prev (not sigs and timestamps)? */ bool nannounce_different(struct gossip_store *gs, const struct node *node, - const u8 *nannounce) + const u8 *nannounce, + bool *only_missing_tlv) { - const u8 *oparts[2], *nparts[2]; - size_t osizes[2], nsizes[2]; + const u8 *oparts[3], *nparts[3]; + size_t osizes[3], nsizes[3]; const u8 *orig; /* Get last one we have. */ @@ -142,8 +169,13 @@ bool nannounce_different(struct gossip_store *gs, get_nannounce_parts(orig, oparts, osizes); get_nannounce_parts(nannounce, nparts, nsizes); + *only_missing_tlv = memeq(oparts[0], osizes[0], nparts[0], nsizes[0]) + && memeq(oparts[1], osizes[1], nparts[1], nsizes[1]) + && !memeq(oparts[2], osizes[2], nparts[2], nsizes[2]); + return !memeq(oparts[0], osizes[0], nparts[0], nsizes[0]) - || !memeq(oparts[1], osizes[1], nparts[1], nsizes[1]); + || !memeq(oparts[1], osizes[1], nparts[1], nsizes[1]) + || !memeq(oparts[2], osizes[2], nparts[2], nsizes[2]); } /* This routine created a `node_announcement` for our node, and hands it to @@ -175,8 +207,10 @@ static void update_own_node_announcement(struct daemon *daemon) /* If it's the same as the previous, nothing to do. */ if (self && self->bcast.index) { u32 next; + bool only_missing_tlv; - if (!nannounce_different(daemon->rstate->gs, self, nannounce)) + if (!nannounce_different(daemon->rstate->gs, self, nannounce, + &only_missing_tlv)) return; /* BOLT #7: diff --git a/gossipd/gossip_generation.h b/gossipd/gossip_generation.h index 5c4857661384..b1277ed0dbc9 100644 --- a/gossipd/gossip_generation.h +++ b/gossipd/gossip_generation.h @@ -29,7 +29,8 @@ bool cupdate_different(struct gossip_store *gs, * node->bcast.index must be non-zero! */ bool nannounce_different(struct gossip_store *gs, const struct node *node, - const u8 *nannounce); + const u8 *nannounce, + bool *only_missing_tlv); /* Should we announce our own node? Called at strategic places. */ void maybe_send_own_node_announce(struct daemon *daemon); diff --git a/gossipd/routing.c b/gossipd/routing.c index ed79c82a8161..a64071d188f1 100644 --- a/gossipd/routing.c +++ b/gossipd/routing.c @@ -2485,6 +2485,8 @@ bool routing_add_node_announcement(struct routing_state *rstate, } if (node->bcast.index) { + bool only_tlv_diff; + if (index != 0) { status_broken("gossip_store node_announcement %u replaces %u!", index, node->bcast.index); @@ -2499,7 +2501,8 @@ bool routing_add_node_announcement(struct routing_state *rstate, /* Allow redundant updates once every 7 days */ if (timestamp < node->bcast.timestamp + GOSSIP_PRUNE_INTERVAL(rstate->dev_fast_gossip_prune) / 2 - && !nannounce_different(rstate->gs, node, msg)) { + && !nannounce_different(rstate->gs, node, msg, + &only_tlv_diff)) { SUPERVERBOSE( "Ignoring redundant nannounce for %s" " (last %u, now %u)", diff --git a/gossipd/test/run-bench-find_route.c b/gossipd/test/run-bench-find_route.c index 0772b7d2348f..661f08bc51d0 100644 --- a/gossipd/test/run-bench-find_route.c +++ b/gossipd/test/run-bench-find_route.c @@ -64,7 +64,8 @@ void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memt /* Generated stub for nannounce_different */ bool nannounce_different(struct gossip_store *gs UNNEEDED, const struct node *node UNNEEDED, - const u8 *nannounce UNNEEDED) + const u8 *nannounce UNNEEDED, + bool *only_missing_tlv UNNEEDED) { fprintf(stderr, "nannounce_different called!\n"); abort(); } /* Generated stub for notleak_ */ void *notleak_(const void *ptr UNNEEDED, bool plus_children UNNEEDED) diff --git a/gossipd/test/run-check_channel_announcement.c b/gossipd/test/run-check_channel_announcement.c index cc77a3414819..76de7a36a164 100644 --- a/gossipd/test/run-check_channel_announcement.c +++ b/gossipd/test/run-check_channel_announcement.c @@ -103,7 +103,8 @@ void memleak_remove_intmap_(struct htable *memtable UNNEEDED, const struct intma /* Generated stub for nannounce_different */ bool nannounce_different(struct gossip_store *gs UNNEEDED, const struct node *node UNNEEDED, - const u8 *nannounce UNNEEDED) + const u8 *nannounce UNNEEDED, + bool *only_missing_tlv UNNEEDED) { fprintf(stderr, "nannounce_different called!\n"); abort(); } /* Generated stub for new_reltimer_ */ struct oneshot *new_reltimer_(struct timers *timers UNNEEDED, diff --git a/gossipd/test/run-check_node_announcement.c b/gossipd/test/run-check_node_announcement.c new file mode 100644 index 000000000000..5017ce3d14c2 --- /dev/null +++ b/gossipd/test/run-check_node_announcement.c @@ -0,0 +1,147 @@ +#include "../gossip_generation.c" +#include +#include +#include + +/* AUTOGENERATED MOCKS START */ +/* Generated stub for find_peer */ +struct peer *find_peer(struct daemon *daemon UNNEEDED, const struct node_id *id UNNEEDED) +{ fprintf(stderr, "find_peer called!\n"); abort(); } +/* Generated stub for fmt_wireaddr_without_port */ +char *fmt_wireaddr_without_port(const tal_t *ctx UNNEEDED, const struct wireaddr *a UNNEEDED) +{ fprintf(stderr, "fmt_wireaddr_without_port called!\n"); abort(); } +/* Generated stub for fromwire_gossipd_local_channel_update */ +bool fromwire_gossipd_local_channel_update(const void *p UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED, bool *disable UNNEEDED, u16 *cltv_expiry_delta UNNEEDED, struct amount_msat *htlc_minimum_msat UNNEEDED, u32 *fee_base_msat UNNEEDED, u32 *fee_proportional_millionths UNNEEDED, struct amount_msat *htlc_maximum_msat UNNEEDED) +{ fprintf(stderr, "fromwire_gossipd_local_channel_update called!\n"); abort(); } +/* Generated stub for fromwire_hsmd_cupdate_sig_reply */ +bool fromwire_hsmd_cupdate_sig_reply(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u8 **cu UNNEEDED) +{ fprintf(stderr, "fromwire_hsmd_cupdate_sig_reply called!\n"); abort(); } +/* Generated stub for fromwire_hsmd_node_announcement_sig_reply */ +bool fromwire_hsmd_node_announcement_sig_reply(const void *p UNNEEDED, secp256k1_ecdsa_signature *signature UNNEEDED) +{ fprintf(stderr, "fromwire_hsmd_node_announcement_sig_reply called!\n"); abort(); } +/* Generated stub for get_node */ +struct node *get_node(struct routing_state *rstate UNNEEDED, + const struct node_id *id UNNEEDED) +{ fprintf(stderr, "get_node called!\n"); abort(); } +/* Generated stub for gossip_time_now */ +struct timeabs gossip_time_now(const struct routing_state *rstate UNNEEDED) +{ fprintf(stderr, "gossip_time_now called!\n"); abort(); } +/* Generated stub for handle_channel_update */ +u8 *handle_channel_update(struct routing_state *rstate UNNEEDED, const u8 *update TAKES UNNEEDED, + struct peer *peer UNNEEDED, + struct short_channel_id *unknown_scid UNNEEDED, + bool force UNNEEDED) +{ fprintf(stderr, "handle_channel_update called!\n"); abort(); } +/* Generated stub for handle_node_announcement */ +u8 *handle_node_announcement(struct routing_state *rstate UNNEEDED, const u8 *node UNNEEDED, + struct peer *peer UNNEEDED, bool *was_unknown UNNEEDED) +{ fprintf(stderr, "handle_node_announcement called!\n"); abort(); } +/* Generated stub for json_add_member */ +void json_add_member(struct json_stream *js UNNEEDED, + const char *fieldname UNNEEDED, + bool quote UNNEEDED, + const char *fmt UNNEEDED, ...) +{ fprintf(stderr, "json_add_member called!\n"); abort(); } +/* Generated stub for json_member_direct */ +char *json_member_direct(struct json_stream *js UNNEEDED, + const char *fieldname UNNEEDED, size_t extra UNNEEDED) +{ fprintf(stderr, "json_member_direct called!\n"); abort(); } +/* Generated stub for json_object_end */ +void json_object_end(struct json_stream *js UNNEEDED) +{ fprintf(stderr, "json_object_end called!\n"); abort(); } +/* Generated stub for json_object_start */ +void json_object_start(struct json_stream *ks UNNEEDED, const char *fieldname UNNEEDED) +{ fprintf(stderr, "json_object_start called!\n"); abort(); } +/* Generated stub for new_reltimer_ */ +struct oneshot *new_reltimer_(struct timers *timers UNNEEDED, + const tal_t *ctx UNNEEDED, + struct timerel expire UNNEEDED, + void (*cb)(void *) UNNEEDED, void *arg UNNEEDED) +{ fprintf(stderr, "new_reltimer_ called!\n"); abort(); } +/* Generated stub for notleak_ */ +void *notleak_(const void *ptr UNNEEDED, bool plus_children UNNEEDED) +{ fprintf(stderr, "notleak_ called!\n"); abort(); } +/* Generated stub for queue_peer_msg */ +void queue_peer_msg(struct peer *peer UNNEEDED, const u8 *msg TAKES UNNEEDED) +{ fprintf(stderr, "queue_peer_msg called!\n"); abort(); } +/* Generated stub for status_failed */ +void status_failed(enum status_failreason code UNNEEDED, + const char *fmt UNNEEDED, ...) +{ fprintf(stderr, "status_failed called!\n"); abort(); } +/* Generated stub for status_fmt */ +void status_fmt(enum log_level level UNNEEDED, + const struct node_id *peer UNNEEDED, + const char *fmt UNNEEDED, ...) + +{ fprintf(stderr, "status_fmt called!\n"); abort(); } +/* Generated stub for towire_hsmd_cupdate_sig_req */ +u8 *towire_hsmd_cupdate_sig_req(const tal_t *ctx UNNEEDED, const u8 *cu UNNEEDED) +{ fprintf(stderr, "towire_hsmd_cupdate_sig_req called!\n"); abort(); } +/* Generated stub for towire_hsmd_node_announcement_sig_req */ +u8 *towire_hsmd_node_announcement_sig_req(const tal_t *ctx UNNEEDED, const u8 *announcement UNNEEDED) +{ fprintf(stderr, "towire_hsmd_node_announcement_sig_req called!\n"); abort(); } +/* Generated stub for towire_wireaddr */ +void towire_wireaddr(u8 **pptr UNNEEDED, const struct wireaddr *addr UNNEEDED) +{ fprintf(stderr, "towire_wireaddr called!\n"); abort(); } +/* Generated stub for wire_sync_read */ +u8 *wire_sync_read(const tal_t *ctx UNNEEDED, int fd UNNEEDED) +{ fprintf(stderr, "wire_sync_read called!\n"); abort(); } +/* Generated stub for wire_sync_write */ +bool wire_sync_write(int fd UNNEEDED, const void *msg TAKES UNNEEDED) +{ fprintf(stderr, "wire_sync_write called!\n"); abort(); } +/* AUTOGENERATED MOCKS END */ + +/* Overwriting this to return test data */ +const u8 *gossip_store_get(const tal_t *ctx, + struct gossip_store *gs, + u64 offset) +{ + /* No TLV, different */ + if (offset == 0) + return tal_hexdata(ctx, "01010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000078000000802aaa260b145790266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c035180266e453454e494f524245414d000000000000000000000000000000000000000000000000", strlen("01010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000078000000802aaa260b145790266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c035180266e453454e494f524245414d000000000000000000000000000000000000000000000000")); + + /* No TLV, same */ + if (offset == 1) + return tal_hexdata(ctx, "01017d49b51b7d3772636c09901df78c81faa1a7f045e329366ad779ecbaf0cc07f764d8ffd3596ef6802fd0e4c5c180c74fb3dfb14aae493ed48d35a3df75c20eca00078000000802aaa260b14569022d223620a359a47ff7f7ac447c85c46c923da53389221a0054c11c1e3ca31d59022d2253494c454e544152544953542d3236352d67373833393533312d6d6f646465640000", strlen("01017d49b51b7d3772636c09901df78c81faa1a7f045e329366ad779ecbaf0cc07f764d8ffd3596ef6802fd0e4c5c180c74fb3dfb14aae493ed48d35a3df75c20eca00078000000802aaa260b14569022d223620a359a47ff7f7ac447c85c46c923da53389221a0054c11c1e3ca31d59022d2253494c454e544152544953542d3236352d67373833393533312d6d6f646465640000")); + + /* Same, with TLV */ + if (offset == 2) + return tal_hexdata(ctx, "0101069628d227649cc2823d94647ad08ea34ad24e7eea95b7a0249bc83e73efefa6072cab1841f0ef3e6d7f4c4140b7b1b13049eb0d85941d7d7bd30c921bfd550300078000000802aaa260b1496f0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c035180266e453454e494f524245414d000000000000000000000000000000000000000000000000010c0014000003e80096001607d0", strlen("0101069628d227649cc2823d94647ad08ea34ad24e7eea95b7a0249bc83e73efefa6072cab1841f0ef3e6d7f4c4140b7b1b13049eb0d85941d7d7bd30c921bfd550300078000000802aaa260b1496f0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c035180266e453454e494f524245414d000000000000000000000000000000000000000000000000010c0014000003e80096001607d0")); + + return NULL; +} + +int main(int argc, char *argv[]) +{ + struct node node; + bool only_missing_tlv; + u8 *ann; + + common_setup(argv[0]); + + /* No TLV checks */ + node.bcast.index = 1; + ann = tal_hexdata(tmpctx, "01017d49b51b7d3772636c09901df78c81faa1a7f045e329366ad779ecbaf0cc07f764d8ffd3596ef6802fd0e4c5c180c74fb3dfb14aae493ed48d35a3df75c20eca00078000000802aaa260b14569022d223620a359a47ff7f7ac447c85c46c923da53389221a0054c11c1e3ca31d59022d2253494c454e544152544953542d3236352d67373833393533312d6d6f646465640000", strlen("01017d49b51b7d3772636c09901df78c81faa1a7f045e329366ad779ecbaf0cc07f764d8ffd3596ef6802fd0e4c5c180c74fb3dfb14aae493ed48d35a3df75c20eca00078000000802aaa260b14569022d223620a359a47ff7f7ac447c85c46c923da53389221a0054c11c1e3ca31d59022d2253494c454e544152544953542d3236352d67373833393533312d6d6f646465640000")); + assert(!nannounce_different(NULL, &node, ann, &only_missing_tlv)); + assert(!only_missing_tlv); + + node.bcast.index = 0; + assert(nannounce_different(NULL, &node, ann, &only_missing_tlv)); + assert(!only_missing_tlv); + + /* TLV checks */ + ann = tal_hexdata(tmpctx, "0101069628d227649cc2823d94647ad08ea34ad24e7eea95b7a0249bc83e73efefa6072cab1841f0ef3e6d7f4c4140b7b1b13049eb0d85941d7d7bd30c921bfd550300078000000802aaa260b1496f0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c035180266e453454e494f524245414d000000000000000000000000000000000000000000000000010c0014000003e80096001607d0", strlen("0101069628d227649cc2823d94647ad08ea34ad24e7eea95b7a0249bc83e73efefa6072cab1841f0ef3e6d7f4c4140b7b1b13049eb0d85941d7d7bd30c921bfd550300078000000802aaa260b1496f0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c035180266e453454e494f524245414d000000000000000000000000000000000000000000000000010c0014000003e80096001607d0")); + + node.bcast.index = 2; + assert(!nannounce_different(NULL, &node, ann, &only_missing_tlv)); + assert(!only_missing_tlv); + + /* Tweak the last, check that it fails */ + node.bcast.index = 2; + ann[tal_count(ann) - 1]++; + assert(nannounce_different(NULL, &node, ann, &only_missing_tlv)); + assert(only_missing_tlv); + + common_shutdown(); + return 0; +} diff --git a/gossipd/test/run-find_route-specific.c b/gossipd/test/run-find_route-specific.c index 64060092c2cb..3835136f2e4c 100644 --- a/gossipd/test/run-find_route-specific.c +++ b/gossipd/test/run-find_route-specific.c @@ -50,7 +50,8 @@ void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memt /* Generated stub for nannounce_different */ bool nannounce_different(struct gossip_store *gs UNNEEDED, const struct node *node UNNEEDED, - const u8 *nannounce UNNEEDED) + const u8 *nannounce UNNEEDED, + bool *only_missing_tlv UNNEEDED) { fprintf(stderr, "nannounce_different called!\n"); abort(); } /* Generated stub for notleak_ */ void *notleak_(const void *ptr UNNEEDED, bool plus_children UNNEEDED) diff --git a/gossipd/test/run-find_route.c b/gossipd/test/run-find_route.c index 41400bf2cd05..0ed7524d19f1 100644 --- a/gossipd/test/run-find_route.c +++ b/gossipd/test/run-find_route.c @@ -50,7 +50,8 @@ void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memt /* Generated stub for nannounce_different */ bool nannounce_different(struct gossip_store *gs UNNEEDED, const struct node *node UNNEEDED, - const u8 *nannounce UNNEEDED) + const u8 *nannounce UNNEEDED, + bool *only_missing_tlv UNNEEDED) { fprintf(stderr, "nannounce_different called!\n"); abort(); } /* Generated stub for notleak_ */ void *notleak_(const void *ptr UNNEEDED, bool plus_children UNNEEDED) diff --git a/gossipd/test/run-overlong.c b/gossipd/test/run-overlong.c index 2a16642f7026..1d8e6dd0864c 100644 --- a/gossipd/test/run-overlong.c +++ b/gossipd/test/run-overlong.c @@ -50,7 +50,8 @@ void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memt /* Generated stub for nannounce_different */ bool nannounce_different(struct gossip_store *gs UNNEEDED, const struct node *node UNNEEDED, - const u8 *nannounce UNNEEDED) + const u8 *nannounce UNNEEDED, + bool *only_missing_tlv UNNEEDED) { fprintf(stderr, "nannounce_different called!\n"); abort(); } /* Generated stub for notleak_ */ void *notleak_(const void *ptr UNNEEDED, bool plus_children UNNEEDED) diff --git a/gossipd/test/run-txout_failure.c b/gossipd/test/run-txout_failure.c index 044e8fed16ff..bf1df6a3e7b1 100644 --- a/gossipd/test/run-txout_failure.c +++ b/gossipd/test/run-txout_failure.c @@ -70,7 +70,8 @@ void memleak_remove_intmap_(struct htable *memtable UNNEEDED, const struct intma /* Generated stub for nannounce_different */ bool nannounce_different(struct gossip_store *gs UNNEEDED, const struct node *node UNNEEDED, - const u8 *nannounce UNNEEDED) + const u8 *nannounce UNNEEDED, + bool *only_missing_tlv UNNEEDED) { fprintf(stderr, "nannounce_different called!\n"); abort(); } /* Generated stub for notleak_ */ void *notleak_(const void *ptr UNNEEDED, bool plus_children UNNEEDED) From 30818b56b1232a31fac00d60d3f2e0b1f937f822 Mon Sep 17 00:00:00 2001 From: niftynei Date: Fri, 28 May 2021 11:32:08 -0500 Subject: [PATCH 04/56] gossipd: signal whether node_ann is updated, are we starting up? If there's a rate-card for liquidity, we don't know about it until after startup (the plugin *should* call us at init to tell us what their current rates are) --- common/gossip_constants.h | 4 ++ gossipd/gossip_generation.c | 133 +++++++++++++++++++++++++++++------- gossipd/gossip_generation.h | 2 +- gossipd/gossipd.c | 6 +- 4 files changed, 116 insertions(+), 29 deletions(-) diff --git a/common/gossip_constants.h b/common/gossip_constants.h index e5e652092070..dac2562eb9fb 100644 --- a/common/gossip_constants.h +++ b/common/gossip_constants.h @@ -47,6 +47,10 @@ #define GOSSIP_MIN_INTERVAL(dev_fast_gossip_flag) \ DEV_FAST_GOSSIP(dev_fast_gossip_flag, 5, 300) +/* How long to wait at start for the plugin to callback with liquidity ad */ +#define GOSSIP_NANN_STARTUP_DELAY(dev_fast_gossip_flag) \ + DEV_FAST_GOSSIP(dev_fast_gossip_flag, 8, 60) + /* BOLT #7: * * - SHOULD flush outgoing gossip messages once every 60 seconds, diff --git a/gossipd/gossip_generation.c b/gossipd/gossip_generation.c index 7676cf7c357b..b3d9ce95006b 100644 --- a/gossipd/gossip_generation.c +++ b/gossipd/gossip_generation.c @@ -178,6 +178,37 @@ bool nannounce_different(struct gossip_store *gs, || !memeq(oparts[2], osizes[2], nparts[2], nsizes[2]); } +static void sign_and_send_nannounce(struct daemon *daemon, + u8 *nannounce, + u32 timestamp) +{ + secp256k1_ecdsa_signature sig; + u8 *msg, *err; + + /* Ask hsmd to sign it (synchronous) */ + if (!wire_sync_write(HSM_FD, take(towire_hsmd_node_announcement_sig_req(NULL, nannounce)))) + status_failed(STATUS_FAIL_MASTER_IO, "Could not write to HSM: %s", strerror(errno)); + + msg = wire_sync_read(tmpctx, HSM_FD); + if (!fromwire_hsmd_node_announcement_sig_reply(msg, &sig)) + status_failed(STATUS_FAIL_MASTER_IO, "HSM returned an invalid node_announcement sig"); + + /* We got the signature for our provisional node_announcement back + * from the HSM, create the real announcement and forward it to + * gossipd so it can take care of forwarding it. */ + nannounce = create_node_announcement(NULL, daemon, &sig, + timestamp, daemon->rates); + + /* This injects it into the routing code in routing.c; it should not + * reject it! */ + err = handle_node_announcement(daemon->rstate, take(nannounce), + NULL, NULL); + if (err) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "rejected own node announcement: %s", + tal_hex(tmpctx, err)); +} + /* This routine created a `node_announcement` for our node, and hands it to * the routing.c code like any other `node_announcement`. Such announcements * are only accepted if there is an announced channel associated with that node @@ -185,8 +216,7 @@ bool nannounce_different(struct gossip_store *gs, static void update_own_node_announcement(struct daemon *daemon) { u32 timestamp = gossip_time_now(daemon->rstate).ts.tv_sec; - secp256k1_ecdsa_signature sig; - u8 *msg, *nannounce, *err; + u8 *nannounce; struct node *self = get_node(daemon->rstate, &daemon->id); /* Discard existing timer. */ @@ -203,7 +233,6 @@ static void update_own_node_announcement(struct daemon *daemon) timestamp, daemon->rates); - /* If it's the same as the previous, nothing to do. */ if (self && self->bcast.index) { u32 next; @@ -226,6 +255,7 @@ static void update_own_node_announcement(struct daemon *daemon) if (timestamp < next) { status_debug("node_announcement: delaying %u secs", next - timestamp); + daemon->node_announce_timer = new_reltimer(&daemon->timers, daemon, @@ -236,32 +266,83 @@ static void update_own_node_announcement(struct daemon *daemon) } } - /* Ask hsmd to sign it (synchronous) */ - if (!wire_sync_write(HSM_FD, take(towire_hsmd_node_announcement_sig_req(NULL, nannounce)))) - status_failed(STATUS_FAIL_MASTER_IO, "Could not write to HSM: %s", strerror(errno)); + sign_and_send_nannounce(daemon, nannounce, timestamp); +} - msg = wire_sync_read(tmpctx, HSM_FD); - if (!fromwire_hsmd_node_announcement_sig_reply(msg, &sig)) - status_failed(STATUS_FAIL_MASTER_IO, "HSM returned an invalid node_announcement sig"); +static void update_own_node_announce_startup(struct daemon *daemon) +{ + u32 timestamp = gossip_time_now(daemon->rstate).ts.tv_sec; + u8 *nannounce; + struct node *self = get_node(daemon->rstate, &daemon->id); - /* We got the signature for our provisional node_announcement back - * from the HSM, create the real announcement and forward it to - * gossipd so it can take care of forwarding it. */ - nannounce = create_node_announcement(NULL, daemon, &sig, - timestamp, daemon->rates); + /* Discard existing timer. */ + daemon->node_announce_timer = tal_free(daemon->node_announce_timer); - /* This injects it into the routing code in routing.c; it should not - * reject it! */ - err = handle_node_announcement(daemon->rstate, take(nannounce), - NULL, NULL); - if (err) - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "rejected own node announcement: %s", - tal_hex(tmpctx, err)); + /* If we ever use set-based propagation, ensuring the toggle the lower + * bit in consecutive timestamps makes it more robust. */ + if (self && self->bcast.index + && (timestamp & 1) == (self->bcast.timestamp & 1)) + timestamp++; + + /* Make unsigned announcement. */ + nannounce = create_node_announcement(tmpctx, daemon, NULL, + timestamp, + daemon->rates); + + + /* If it's the same as the previous, nothing to do. */ + if (self && self->bcast.index) { + u32 next; + bool only_missing_tlv; + + if (!nannounce_different(daemon->rstate->gs, self, nannounce, + &only_missing_tlv)) + return; + + /* Missing liquidity_ad, maybe we'll get plugin callback */ + if (only_missing_tlv) { + u32 delay = GOSSIP_NANN_STARTUP_DELAY(daemon->rstate->dev_fast_gossip); + status_debug("node_announcement: delaying" + " %u secs at start", delay); + + daemon->node_announce_timer + = new_reltimer(&daemon->timers, + daemon, + time_from_sec(delay), + update_own_node_announcement, + daemon); + return; + } + + /* BOLT #7: + * + * The origin node: + * - MUST set `timestamp` to be greater than that of any + * previous `node_announcement` it has previously created. + */ + /* We do better: never send them within more than 5 minutes. */ + next = self->bcast.timestamp + + GOSSIP_MIN_INTERVAL(daemon->rstate->dev_fast_gossip); + + if (timestamp < next) { + status_debug("node_announcement: delaying %u secs", + next - timestamp); + + daemon->node_announce_timer + = new_reltimer(&daemon->timers, + daemon, + time_from_sec(next - timestamp), + update_own_node_announcement, + daemon); + return; + } + } + + sign_and_send_nannounce(daemon, nannounce, timestamp); } /* Should we announce our own node? Called at strategic places. */ -void maybe_send_own_node_announce(struct daemon *daemon) +void maybe_send_own_node_announce(struct daemon *daemon, bool startup) { /* We keep an internal flag in the routing code to say we've announced * a local channel. The alternative would be to have it make a @@ -270,8 +351,10 @@ void maybe_send_own_node_announce(struct daemon *daemon) if (!daemon->rstate->local_channel_announced) return; - update_own_node_announcement(daemon); - daemon->rstate->local_channel_announced = false; + if (startup) + update_own_node_announce_startup(daemon); + else + update_own_node_announcement(daemon); } /* Our timer callbacks take a single argument, so we marshall everything diff --git a/gossipd/gossip_generation.h b/gossipd/gossip_generation.h index b1277ed0dbc9..d58f5151e56b 100644 --- a/gossipd/gossip_generation.h +++ b/gossipd/gossip_generation.h @@ -33,7 +33,7 @@ bool nannounce_different(struct gossip_store *gs, bool *only_missing_tlv); /* Should we announce our own node? Called at strategic places. */ -void maybe_send_own_node_announce(struct daemon *daemon); +void maybe_send_own_node_announce(struct daemon *daemon, bool startup); /* This is a refresh of a local channel: sends an update if one is needed. */ void refresh_local_channel(struct daemon *daemon, diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index 04277d260e08..b6aa881cf2ff 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -289,7 +289,7 @@ static u8 *handle_channel_update_msg(struct peer *peer, const u8 *msg) * routing until you have both anyway. For this reason, we might have * just sent out our own channel_announce, so we check if it's time to * send a node_announcement too. */ - maybe_send_own_node_announce(peer->daemon); + maybe_send_own_node_announce(peer->daemon, false); return NULL; } @@ -1132,7 +1132,7 @@ static struct io_plan *gossip_init(struct io_conn *conn, /* If that announced channels, we can announce ourselves (options * or addresses might have changed!) */ - maybe_send_own_node_announce(daemon); + maybe_send_own_node_announce(daemon, true); /* Start the twice- weekly refresh timer. */ notleak(new_reltimer(&daemon->timers, daemon, @@ -1710,7 +1710,7 @@ static struct io_plan *handle_txout_reply(struct io_conn *conn, /* Anywhere we might have announced a channel, we check if it's time to * announce ourselves (ie. if we just announced our own first channel) */ - maybe_send_own_node_announce(daemon); + maybe_send_own_node_announce(daemon, false); return daemon_conn_read_next(conn, daemon->master); } From cb2e5d9474468d58d6e7e6fe646837193f9c469b Mon Sep 17 00:00:00 2001 From: niftynei Date: Fri, 28 May 2021 11:39:52 -0500 Subject: [PATCH 05/56] setleaserates: new RPC to pass in lease rates Changelog-Added: JSON-RPC: new RPC `setleaserates`, for passing in the rates to advertise for a channel lease (option_will_fund) --- gossipd/gossipd.c | 21 +++++++++++ gossipd/gossipd_wire.csv | 4 +++ gossipd/gossipd_wiregen.c | 26 +++++++++++++- gossipd/gossipd_wiregen.h | 10 +++++- lightningd/gossip_control.c | 69 +++++++++++++++++++++++++++++++++++++ tests/test_gossip.py | 22 ++++++++++++ 6 files changed, 150 insertions(+), 2 deletions(-) diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index b6aa881cf2ff..024b7f602322 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -1762,6 +1762,24 @@ static struct io_plan *inject_gossip(struct io_conn *conn, return daemon_conn_read_next(conn, daemon->master); } +static struct io_plan *handle_new_lease_rates(struct io_conn *conn, + struct daemon *daemon, + const u8 *msg) +{ + struct lease_rates *rates = tal(daemon, struct lease_rates); + + if (!fromwire_gossipd_new_lease_rates(msg, rates)) + master_badmsg(WIRE_GOSSIPD_NEW_LEASE_RATES, msg); + + tal_free(daemon->rates); + daemon->rates = rates; + + /* Send the update over to the peer */ + maybe_send_own_node_announce(daemon, false); + + return daemon_conn_read_next(conn, daemon->master); +} + /*~ This is where lightningd tells us that a channel's funding transaction has * been spent. */ static struct io_plan *handle_outpoint_spent(struct io_conn *conn, @@ -1861,6 +1879,9 @@ static struct io_plan *recv_req(struct io_conn *conn, case WIRE_GOSSIPD_ADDGOSSIP: return inject_gossip(conn, daemon, msg); + case WIRE_GOSSIPD_NEW_LEASE_RATES: + return handle_new_lease_rates(conn, daemon, msg); + #if DEVELOPER case WIRE_GOSSIPD_DEV_SET_MAX_SCIDS_ENCODE_SIZE: return dev_set_max_scids_encode_size(conn, daemon, msg); diff --git a/gossipd/gossipd_wire.csv b/gossipd/gossipd_wire.csv index f9b6e0f61939..83b4f2595a0d 100644 --- a/gossipd/gossipd_wire.csv +++ b/gossipd/gossipd_wire.csv @@ -1,6 +1,7 @@ #include #include #include +#include #include # Initialize the gossip daemon. @@ -166,3 +167,6 @@ msgdata,gossipd_addgossip,msg,u8,len msgtype,gossipd_addgossip_reply,3144 msgdata,gossipd_addgossip_reply,err,wirestring, +# Updated lease rates available +msgtype,gossipd_new_lease_rates,3046 +msgdata,gossipd_new_lease_rates,rates,lease_rates, diff --git a/gossipd/gossipd_wiregen.c b/gossipd/gossipd_wiregen.c index 6e86ca01e0e8..51ce056d1214 100644 --- a/gossipd/gossipd_wiregen.c +++ b/gossipd/gossipd_wiregen.c @@ -50,6 +50,7 @@ const char *gossipd_wire_name(int e) case WIRE_GOSSIPD_SEND_ONIONMSG: return "WIRE_GOSSIPD_SEND_ONIONMSG"; case WIRE_GOSSIPD_ADDGOSSIP: return "WIRE_GOSSIPD_ADDGOSSIP"; case WIRE_GOSSIPD_ADDGOSSIP_REPLY: return "WIRE_GOSSIPD_ADDGOSSIP_REPLY"; + case WIRE_GOSSIPD_NEW_LEASE_RATES: return "WIRE_GOSSIPD_NEW_LEASE_RATES"; } snprintf(invalidbuf, sizeof(invalidbuf), "INVALID %i", e); @@ -89,6 +90,7 @@ bool gossipd_wire_is_defined(u16 type) case WIRE_GOSSIPD_SEND_ONIONMSG:; case WIRE_GOSSIPD_ADDGOSSIP:; case WIRE_GOSSIPD_ADDGOSSIP_REPLY:; + case WIRE_GOSSIPD_NEW_LEASE_RATES:; return true; } return false; @@ -1057,4 +1059,26 @@ bool fromwire_gossipd_addgossip_reply(const tal_t *ctx, const void *p, wirestrin *err = fromwire_wirestring(ctx, &cursor, &plen); return cursor != NULL; } -// SHA256STAMP:a0d7494995d7f95fb7df295bab9d865e18670f15243116a0aaa9b9548534b922 + +/* WIRE: GOSSIPD_NEW_LEASE_RATES */ +/* Updated lease rates available */ +u8 *towire_gossipd_new_lease_rates(const tal_t *ctx, const struct lease_rates *rates) +{ + u8 *p = tal_arr(ctx, u8, 0); + + towire_u16(&p, WIRE_GOSSIPD_NEW_LEASE_RATES); + towire_lease_rates(&p, rates); + + return memcheck(p, tal_count(p)); +} +bool fromwire_gossipd_new_lease_rates(const void *p, struct lease_rates *rates) +{ + const u8 *cursor = p; + size_t plen = tal_count(p); + + if (fromwire_u16(&cursor, &plen) != WIRE_GOSSIPD_NEW_LEASE_RATES) + return false; + fromwire_lease_rates(&cursor, &plen, rates); + return cursor != NULL; +} +// SHA256STAMP:a9b05ef5740445f1074c703bb85758e50286d48fc21e723d40f61d3febd9df12 diff --git a/gossipd/gossipd_wiregen.h b/gossipd/gossipd_wiregen.h index 0e989c517672..64ad7ee9e3cd 100644 --- a/gossipd/gossipd_wiregen.h +++ b/gossipd/gossipd_wiregen.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -67,6 +68,8 @@ enum gossipd_wire { WIRE_GOSSIPD_ADDGOSSIP = 3044, /* Empty string means no problem. */ WIRE_GOSSIPD_ADDGOSSIP_REPLY = 3144, + /* Updated lease rates available */ + WIRE_GOSSIPD_NEW_LEASE_RATES = 3046, }; const char *gossipd_wire_name(int e); @@ -223,6 +226,11 @@ bool fromwire_gossipd_addgossip(const tal_t *ctx, const void *p, u8 **msg); u8 *towire_gossipd_addgossip_reply(const tal_t *ctx, const wirestring *err); bool fromwire_gossipd_addgossip_reply(const tal_t *ctx, const void *p, wirestring **err); +/* WIRE: GOSSIPD_NEW_LEASE_RATES */ +/* Updated lease rates available */ +u8 *towire_gossipd_new_lease_rates(const tal_t *ctx, const struct lease_rates *rates); +bool fromwire_gossipd_new_lease_rates(const void *p, struct lease_rates *rates); + #endif /* LIGHTNING_GOSSIPD_GOSSIPD_WIREGEN_H */ -// SHA256STAMP:a0d7494995d7f95fb7df295bab9d865e18670f15243116a0aaa9b9548534b922 +// SHA256STAMP:a9b05ef5740445f1074c703bb85758e50286d48fc21e723d40f61d3febd9df12 diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index 38ceac648123..bb213f4cdc3f 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -141,6 +141,7 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds) case WIRE_GOSSIPD_GET_STRIPPED_CUPDATE: case WIRE_GOSSIPD_GET_TXOUT_REPLY: case WIRE_GOSSIPD_OUTPOINT_SPENT: + case WIRE_GOSSIPD_NEW_LEASE_RATES: case WIRE_GOSSIPD_GET_INCOMING_CHANNELS: case WIRE_GOSSIPD_DEV_SET_MAX_SCIDS_ENCODE_SIZE: case WIRE_GOSSIPD_DEV_SUPPRESS: @@ -460,6 +461,74 @@ static const struct json_command getroute_command = { }; AUTODATA(json_command, &getroute_command); +static struct command_result *json_setleaserates(struct command *cmd, + const char *buffer, + const jsmntok_t *obj UNNEEDED, + const jsmntok_t *params) +{ + struct json_stream *res; + struct lease_rates *rates; + struct amount_sat *lease_base_sat; + struct amount_msat *channel_fee_base_msat; + u32 *lease_basis, *channel_fee_max_ppt, *funding_weight; + + if (!param(cmd, buffer, params, + p_req("lease_fee_base_msat", param_sat, &lease_base_sat), + p_req("lease_fee_basis", param_number, &lease_basis), + p_req("funding_weight", param_number, &funding_weight), + p_req("channel_fee_max_base_msat", param_msat, + &channel_fee_base_msat), + p_req("channel_fee_max_proportional_thousandths", + param_number, &channel_fee_max_ppt), + NULL)) + return command_param_failed(); + + rates = tal(tmpctx, struct lease_rates); + rates->lease_fee_basis = *lease_basis; + rates->lease_fee_base_sat = lease_base_sat->satoshis; /* Raw: conversion */ + rates->channel_fee_max_base_msat = channel_fee_base_msat->millisatoshis; /* Raw: conversion */ + + rates->funding_weight = *funding_weight; + rates->channel_fee_max_proportional_thousandths + = *channel_fee_max_ppt; + + /* Gotta check that we didn't overflow */ + if (lease_base_sat->satoshis > rates->lease_fee_base_sat) + return command_fail_badparam(cmd, "lease_fee_base_msat", + buffer, params, "Overflow"); + + if (channel_fee_base_msat->millisatoshis > rates->channel_fee_max_base_msat) + return command_fail_badparam(cmd, "channel_fee_max_base_msat", + buffer, params, "Overflow"); + + /* Call gossipd, let them know we've got new rates */ + subd_send_msg(cmd->ld->gossip, + take(towire_gossipd_new_lease_rates(NULL, rates))); + + res = json_stream_success(cmd); + json_add_amount_sat_only(res, "lease_fee_base_msat", + amount_sat(rates->lease_fee_base_sat)); + json_add_num(res, "lease_fee_basis", rates->lease_fee_basis); + json_add_num(res, "funding_weight", rates->funding_weight); + json_add_amount_msat_only(res, "channel_fee_max_base_msat", + amount_msat(rates->channel_fee_max_base_msat)); + json_add_num(res, "channel_fee_max_proportional_thousandths", + rates->channel_fee_max_proportional_thousandths); + + return command_success(cmd, res); +} + +static const struct json_command setleaserates_command = { + "setleaserates", + "channels", + json_setleaserates, + "Called by plugin to set the node's present channel lease rates." + " Not to be set without having a plugin which can handle" + " `openchannel2` hooks.", +}; + +AUTODATA(json_command, &setleaserates_command); + static void json_add_halfchan(struct json_stream *response, const struct gossip_getchannels_entry *e, int idx) diff --git a/tests/test_gossip.py b/tests/test_gossip.py index abf6841e01c6..d1d77a0e4719 100644 --- a/tests/test_gossip.py +++ b/tests/test_gossip.py @@ -1084,6 +1084,28 @@ def test_node_reannounce(node_factory, bitcoind, chainparams): # Won't have queued up another one, either. assert not l1.daemon.is_in_log('node_announcement: delaying') + # Try updating the lease rates ad + ad = l1.rpc.call('setleaserates', + {'lease_fee_base_msat': '1000sat', + 'lease_fee_basis': 20, + 'funding_weight': 150, + 'channel_fee_max_base_msat': '2000msat', + 'channel_fee_max_proportional_thousandths': 22}) + + assert ad['lease_fee_base_msat'] == Millisatoshi('1000000msat') + assert ad['lease_fee_basis'] == 20 + assert ad['funding_weight'] == 150 + assert ad['channel_fee_max_base_msat'] == Millisatoshi('2000msat') + assert ad['channel_fee_max_proportional_thousandths'] == 22 + + msgs2 = l1.query_gossip('gossip_timestamp_filter', + genesis_blockhash, + '0', '0xFFFFFFFF', + # Filter out gossip_timestamp_filter, + # channel_announcement and channel_updates. + filters=['0109', '0102', '0100']) + assert msgs != msgs2 + def test_gossipwith(node_factory): l1, l2 = node_factory.line_graph(2, wait_for_announce=True) From 913c93cf8d4275e4e1d994dabe462af51a59d973 Mon Sep 17 00:00:00 2001 From: niftynei Date: Wed, 26 May 2021 18:04:07 -0500 Subject: [PATCH 06/56] option_will_fund: print out lease rates in listnodes Note that we use the names from the spec. Changelog-Added: EXPERIMENTAL JSON-RPC: `listnodes` now includes the `lease_rates`, if available --- common/json_helpers.c | 14 ++++++++++++++ common/json_helpers.h | 5 +++++ lightningd/gossip_control.c | 5 +++++ 3 files changed, 24 insertions(+) diff --git a/common/json_helpers.c b/common/json_helpers.c index 61450a302fa1..924820c78c7f 100644 --- a/common/json_helpers.c +++ b/common/json_helpers.c @@ -13,6 +13,7 @@ #include #include #include +#include bool json_to_bitcoin_amount(const char *buffer, const jsmntok_t *tok, uint64_t *satoshi) @@ -369,3 +370,16 @@ void json_add_preimage(struct json_stream *result, const char *fieldname, json_add_hex(result, fieldname, preimage, sizeof(*preimage)); } +void json_add_lease_rates(struct json_stream *result, + const struct lease_rates *rates) +{ + json_add_amount_sat_only(result, "lease_fee_base_msat", + amount_sat(rates->lease_fee_base_sat)); + json_add_num(result, "lease_fee_basis", rates->lease_fee_basis); + json_add_num(result, "funding_weight", rates->funding_weight); + json_add_amount_msat_only(result, + "channel_fee_max_base_msat", + amount_msat(rates->channel_fee_max_base_msat)); + json_add_num(result, "channel_fee_max_proportional_thousandths", + rates->channel_fee_max_proportional_thousandths); +} diff --git a/common/json_helpers.h b/common/json_helpers.h index 5d0b568f4e34..cfe12c5fd998 100644 --- a/common/json_helpers.h +++ b/common/json_helpers.h @@ -11,6 +11,7 @@ struct amount_msat; struct amount_sat; struct bip340sig; struct channel_id; +struct lease_rates; struct node_id; struct preimage; struct pubkey; @@ -179,4 +180,8 @@ void json_add_psbt(struct json_stream *stream, const char *fieldname, const struct wally_psbt *psbt); +/* Add fields from the lease_rates to a json stream. + * Note that field names are set */ +void json_add_lease_rates(struct json_stream *result, + const struct lease_rates *rates); #endif /* LIGHTNING_COMMON_JSON_HELPERS_H */ diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index bb213f4cdc3f..ac97d345160d 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -277,6 +277,11 @@ static void json_getnodes_reply(struct subd *gossip UNUSED, const u8 *reply, json_add_address(response, NULL, &nodes[i]->addresses[j]); } json_array_end(response); + if (nodes[i]->rates) { + json_object_start(response, "option_will_fund"); + json_add_lease_rates(response, nodes[i]->rates); + json_object_end(response); + } json_object_end(response); } json_array_end(response); From f4f571fce39a3aa0f0c7ace4c30cbbd78e165912 Mon Sep 17 00:00:00 2001 From: niftynei Date: Sat, 29 May 2021 13:56:03 -0500 Subject: [PATCH 07/56] libplugin: add u16_option parsing A couple of the fields for liquidity_ads are u16 --- plugins/libplugin.c | 19 +++++++++++++++++++ plugins/libplugin.h | 1 + 2 files changed, 20 insertions(+) diff --git a/plugins/libplugin.c b/plugins/libplugin.c index f28f5be722ed..e824917241cd 100644 --- a/plugins/libplugin.c +++ b/plugins/libplugin.c @@ -925,6 +925,25 @@ char *u32_option(const char *arg, u32 *i) return NULL; } +char *u16_option(const char *arg, u16 *i) +{ + char *endp; + u64 n; + + errno = 0; + n = strtoul(arg, &endp, 0); + if (*endp || !arg[0]) + return tal_fmt(NULL, "'%s' is not a number", arg); + if (errno) + return tal_fmt(NULL, "'%s' is out of range", arg); + + *i = n; + if (*i != n) + return tal_fmt(NULL, "'%s' is too large (overflow)", arg); + + return NULL; +} + char *bool_option(const char *arg, bool *i) { if (!streq(arg, "true") && !streq(arg, "false")) diff --git a/plugins/libplugin.h b/plugins/libplugin.h index 6ae600fd9b90..e480ed50da32 100644 --- a/plugins/libplugin.h +++ b/plugins/libplugin.h @@ -277,6 +277,7 @@ void plugin_notify_progress(struct command *cmd, /* Standard helpers */ char *u64_option(const char *arg, u64 *i); char *u32_option(const char *arg, u32 *i); +char *u16_option(const char *arg, u16 *i); char *bool_option(const char *arg, bool *i); char *charp_option(const char *arg, char **p); char *flag_option(const char *arg, bool *i); From 421dca9f9890123ed3a4b4167c61aff253504fb0 Mon Sep 17 00:00:00 2001 From: niftynei Date: Thu, 10 Jun 2021 15:30:19 -0500 Subject: [PATCH 08/56] gossipd: turn off lease offers if the rates are empty If received lease rates are empty (all zeroes), turn them off --- common/lease_rates.c | 17 +++++++++++++++++ common/lease_rates.h | 9 +++++++++ gossipd/Makefile | 1 + gossipd/gossipd.c | 8 ++++++-- 4 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 common/lease_rates.c create mode 100644 common/lease_rates.h diff --git a/common/lease_rates.c b/common/lease_rates.c new file mode 100644 index 000000000000..cf0b402448f5 --- /dev/null +++ b/common/lease_rates.c @@ -0,0 +1,17 @@ +#include "config.h" +#include +#include +#include + +bool lease_rates_empty(struct lease_rates *rates) +{ + if (!rates) + return true; + + /* FIXME: why can't i do memeqzero? */ + return rates->funding_weight == 0 + && rates->channel_fee_max_base_msat == 0 + && rates->channel_fee_max_proportional_thousandths == 0 + && rates->lease_fee_base_sat == 0 + && rates->lease_fee_basis == 0; +} diff --git a/common/lease_rates.h b/common/lease_rates.h new file mode 100644 index 000000000000..dd10e79fb57a --- /dev/null +++ b/common/lease_rates.h @@ -0,0 +1,9 @@ +#ifndef LIGHTNING_COMMON_LEASE_RATES_H +#define LIGHTNING_COMMON_LEASE_RATES_H +#include "config.h" +#include + +struct lease_rates; + +bool lease_rates_empty(struct lease_rates *rates); +#endif /* LIGHTNING_COMMON_LEASE_RATES_H */ diff --git a/gossipd/Makefile b/gossipd/Makefile index 7d4f7d70a38b..510ebccf9486 100644 --- a/gossipd/Makefile +++ b/gossipd/Makefile @@ -48,6 +48,7 @@ GOSSIPD_COMMON_OBJS := \ common/status_wiregen.o \ common/gossip_rcvd_filter.o \ common/key_derive.o \ + common/lease_rates.o \ common/memleak.o \ common/msg_queue.o \ common/node_id.o \ diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index 024b7f602322..36738ab315a0 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -1771,8 +1772,11 @@ static struct io_plan *handle_new_lease_rates(struct io_conn *conn, if (!fromwire_gossipd_new_lease_rates(msg, rates)) master_badmsg(WIRE_GOSSIPD_NEW_LEASE_RATES, msg); - tal_free(daemon->rates); - daemon->rates = rates; + daemon->rates = tal_free(daemon->rates); + if (!lease_rates_empty(rates)) + daemon->rates = rates; + else + tal_free(rates); /* Send the update over to the peer */ maybe_send_own_node_announce(daemon, false); From 35f9fcca3d6a318549a7a85624d48eddf0eaca4e Mon Sep 17 00:00:00 2001 From: niftynei Date: Wed, 26 May 2021 18:10:32 -0500 Subject: [PATCH 09/56] funder: make policy a pointer, most places --- plugins/funder.c | 48 +++++++++---------- plugins/funder_policy.c | 80 ++++++++++++++++---------------- plugins/funder_policy.h | 14 +++--- plugins/test/run-funder_policy.c | 14 +++--- 4 files changed, 80 insertions(+), 76 deletions(-) diff --git a/plugins/funder.c b/plugins/funder.c index 1731f7fbd1a2..fc910d23ae39 100644 --- a/plugins/funder.c +++ b/plugins/funder.c @@ -27,7 +27,7 @@ static struct list_head pending_opens; /* Current set policy */ -static struct funder_policy current_policy; +static struct funder_policy *current_policy; struct pending_open { struct list_node list; @@ -757,7 +757,7 @@ json_funderupdate(struct command *cmd, u64 *mod; enum funder_opt *opt; const char *err; - struct funder_policy policy = current_policy; + struct funder_policy *policy = current_policy; if (!param(cmd, buf, params, p_opt("policy", param_funder_opt, &opt), @@ -773,32 +773,32 @@ json_funderupdate(struct command *cmd, return command_param_failed(); if (opt) - policy.opt = *opt; + policy->opt = *opt; if (mod) - policy.mod = *mod; + policy->mod = *mod; if (min_their_funding) - policy.min_their_funding = *min_their_funding; + policy->min_their_funding = *min_their_funding; if (max_their_funding) - policy.max_their_funding = *max_their_funding; + policy->max_their_funding = *max_their_funding; if (per_channel_min) - policy.per_channel_min = *per_channel_min; + policy->per_channel_min = *per_channel_min; if (per_channel_max) - policy.per_channel_max = *per_channel_max; + policy->per_channel_max = *per_channel_max; if (reserve_tank) - policy.reserve_tank = *reserve_tank; + policy->reserve_tank = *reserve_tank; if (fuzz_factor) - policy.fuzz_factor = *fuzz_factor; + policy->fuzz_factor = *fuzz_factor; if (fund_probability) - policy.fund_probability = *fund_probability; + policy->fund_probability = *fund_probability; - err = funder_check_policy(&policy); + err = funder_check_policy(policy); if (err) return command_done_err(cmd, JSONRPC2_INVALID_PARAMS, err, NULL); current_policy = policy; res = jsonrpc_stream_success(cmd); - policy_to_json(res, ¤t_policy); + policy_to_json(res, current_policy); return command_finished(cmd, res); } @@ -819,7 +819,7 @@ static const char *init(struct plugin *p, const char *b, const jsmntok_t *t) list_head_init(&pending_opens); - err = funder_check_policy(¤t_policy); + err = funder_check_policy(current_policy); if (err) plugin_err(p, "Invalid parameter combination: %s", err); @@ -890,7 +890,7 @@ int main(int argc, char **argv) setup_locale(); /* Our default funding policy is fixed (0msat) */ - current_policy = default_funder_policy(FIXED, 0); + current_policy = default_funder_policy(owner, FIXED, 0); plugin_main(argv, init, PLUGIN_RESTARTABLE, true, NULL, @@ -902,57 +902,57 @@ int main(int argc, char **argv) "string", "Policy to use for dual-funding requests." " [match, available, fixed]", - funding_option, ¤t_policy.opt), + funding_option, ¤t_policy->opt), plugin_option("funder-policy-mod", "string", "Percent to apply policy at" " (match/available); or amount to fund" " (fixed)", amount_sat_or_u64_option, - ¤t_policy.mod), + ¤t_policy->mod), plugin_option("funder-min-their-funding", "string", "Minimum funding peer must open with" " to activate our policy", amount_option, - ¤t_policy.min_their_funding), + ¤t_policy->min_their_funding), plugin_option("funder-max-their-funding", "string", "Maximum funding peer may open with" " to activate our policy", amount_option, - ¤t_policy.max_their_funding), + ¤t_policy->max_their_funding), plugin_option("funder-per-channel-min", "string", "Minimum funding we'll add to a channel." " If we can't meet this, we don't fund", amount_option, - ¤t_policy.per_channel_min), + ¤t_policy->per_channel_min), plugin_option("funder-per-channel-max", "string", "Maximum funding we'll add to a channel." " We cap all contributions to this", amount_option, - ¤t_policy.per_channel_max), + ¤t_policy->per_channel_max), plugin_option("funder-reserve-tank", "string", "Amount of funds we'll always leave" " available.", amount_option, - ¤t_policy.reserve_tank), + ¤t_policy->reserve_tank), plugin_option("funder-fuzz-percent", "int", "Percent to fuzz the policy contribution by." " Defaults to 5%. Max is 100%", u32_option, - ¤t_policy.fuzz_factor), + ¤t_policy->fuzz_factor), plugin_option("funder-fund-probability", "int", "Percent of requests to consider." " Defaults to 100%. Setting to 0% will" " disable dual-funding", u32_option, - ¤t_policy.fund_probability), + ¤t_policy->fund_probability), NULL); tal_free(owner); diff --git a/plugins/funder_policy.c b/plugins/funder_policy.c index 956fb15425df..69dabf9bd437 100644 --- a/plugins/funder_policy.c +++ b/plugins/funder_policy.c @@ -35,22 +35,23 @@ char *funding_option(const char *arg, enum funder_opt *opt) } const char *funder_policy_desc(const tal_t *ctx, - struct funder_policy policy) + const struct funder_policy *policy) { - if (policy.opt == FIXED) { - struct amount_sat amt = amount_sat(policy.mod); + if (policy->opt == FIXED) { + struct amount_sat amt = amount_sat(policy->mod); return tal_fmt(ctx, "%s (%s)", - funder_opt_name(policy.opt), + funder_opt_name(policy->opt), type_to_string(ctx, struct amount_sat, &amt)); } else return tal_fmt(ctx, "%s (%"PRIu64"%%)", - funder_opt_name(policy.opt), policy.mod); + funder_opt_name(policy->opt), policy->mod); /* FIXME: add in more info? */ } -struct funder_policy -new_funder_policy(enum funder_opt opt, +struct funder_policy * +new_funder_policy(const tal_t *ctx, + enum funder_opt opt, u64 policy_mod, struct amount_sat min_their_funding, struct amount_sat max_their_funding, @@ -60,31 +61,32 @@ new_funder_policy(enum funder_opt opt, struct amount_sat reserve_tank, u32 fund_probability) { - struct funder_policy policy; + struct funder_policy *policy = tal(ctx, struct funder_policy); - policy.opt = opt; - policy.mod = policy_mod; - policy.min_their_funding = min_their_funding; - policy.max_their_funding = max_their_funding; - policy.per_channel_min = per_channel_min; - policy.per_channel_max = per_channel_max; - policy.fuzz_factor = fuzz_factor; - policy.reserve_tank = reserve_tank; - policy.fund_probability = fund_probability; + policy->opt = opt; + policy->mod = policy_mod; + policy->min_their_funding = min_their_funding; + policy->max_their_funding = max_their_funding; + policy->per_channel_min = per_channel_min; + policy->per_channel_max = per_channel_max; + policy->fuzz_factor = fuzz_factor; + policy->reserve_tank = reserve_tank; + policy->fund_probability = fund_probability; return policy; } -struct funder_policy -default_funder_policy(enum funder_opt policy, +struct funder_policy * +default_funder_policy(const tal_t *ctx, + enum funder_opt policy, u64 policy_mod) { - return new_funder_policy(policy, policy_mod, + return new_funder_policy(ctx, policy, policy_mod, AMOUNT_SAT(10000), AMOUNT_SAT(UINT_MAX), AMOUNT_SAT(10000), AMOUNT_SAT(UINT_MAX), - 5, /* fuzz_factor */ + 0, /* fuzz_factor */ AMOUNT_SAT(0), /* reserve_tank */ 100); } @@ -137,37 +139,37 @@ apply_fuzz(u32 fuzz_factor, struct amount_sat val) } static struct amount_sat -apply_policy(struct funder_policy policy, +apply_policy(struct funder_policy *policy, struct amount_sat their_funding, struct amount_sat available_funds) { struct amount_sat our_funding; - switch (policy.opt) { + switch (policy->opt) { case MATCH: /* if this fails, it implies ludicrous funding offer, *and* * > 100% match. Just Say No, kids. */ if (!amount_sat_scale(&our_funding, their_funding, - policy.mod / 100.0)) + policy->mod / 100.0)) our_funding = AMOUNT_SAT(0); return our_funding; case AVAILABLE: /* Use the 'available_funds' as the starting * point for your contribution */ if (!amount_sat_scale(&our_funding, available_funds, - policy.mod / 100.0)) + policy->mod / 100.0)) abort(); return our_funding; case FIXED: /* Use a static amount */ - return amount_sat(policy.mod); + return amount_sat(policy->mod); } abort(); } const char * -calculate_our_funding(struct funder_policy policy, +calculate_our_funding(struct funder_policy *policy, struct node_id id, struct amount_sat their_funding, struct amount_sat available_funds, @@ -177,7 +179,7 @@ calculate_our_funding(struct funder_policy policy, struct amount_sat avail_channel_space, net_available_funds; /* Are we skipping this one? */ - if (pseudorand(100) >= policy.fund_probability) { + if (pseudorand(100) >= policy->fund_probability) { *our_funding = AMOUNT_SAT(0); return tal_fmt(tmpctx, "Skipping, failed fund_probability test"); @@ -198,7 +200,7 @@ calculate_our_funding(struct funder_policy policy, /* Figure out actual available funds, given our requested * 'reserve_tank' */ if (!amount_sat_sub(&net_available_funds, available_funds, - policy.reserve_tank) + policy->reserve_tank) || amount_sat_eq(net_available_funds, AMOUNT_SAT(0))) { *our_funding = AMOUNT_SAT(0); return tal_fmt(tmpctx, "Reserve tank too low." @@ -206,11 +208,11 @@ calculate_our_funding(struct funder_policy policy, type_to_string(tmpctx, struct amount_sat, &available_funds), type_to_string(tmpctx, struct amount_sat, - &policy.reserve_tank)); + &policy->reserve_tank)); } /* Are they funding enough ? */ - if (amount_sat_less(their_funding, policy.min_their_funding)) { + if (amount_sat_less(their_funding, policy->min_their_funding)) { *our_funding = AMOUNT_SAT(0); return tal_fmt(tmpctx, "Peer's funding too little." " their_funding %s," @@ -218,11 +220,11 @@ calculate_our_funding(struct funder_policy policy, type_to_string(tmpctx, struct amount_sat, &their_funding), type_to_string(tmpctx, struct amount_sat, - &policy.min_their_funding)); + &policy->min_their_funding)); } /* Are they funding too much ? */ - if (amount_sat_greater(their_funding, policy.max_their_funding)) { + if (amount_sat_greater(their_funding, policy->max_their_funding)) { *our_funding = AMOUNT_SAT(0); return tal_fmt(tmpctx, "Peer's funding too much." " their_funding %s," @@ -230,7 +232,7 @@ calculate_our_funding(struct funder_policy policy, type_to_string(tmpctx, struct amount_sat, &their_funding), type_to_string(tmpctx, struct amount_sat, - &policy.max_their_funding)); + &policy->max_their_funding)); } /* What's our amount, given our policy */ @@ -241,7 +243,7 @@ calculate_our_funding(struct funder_policy policy, return NULL; /* our_funding is probably sane, so let's fuzz this amount a bit */ - *our_funding = apply_fuzz(policy.fuzz_factor, *our_funding); + *our_funding = apply_fuzz(policy->fuzz_factor, *our_funding); /* Is our_funding more than we can fit? if so set to avail space */ if (amount_sat_greater(*our_funding, avail_channel_space)) @@ -249,8 +251,8 @@ calculate_our_funding(struct funder_policy policy, /* Is our_funding more than we want to fund in a channel? * if so set at our desired per-channel max */ - if (amount_sat_greater(*our_funding, policy.per_channel_max)) - *our_funding = policy.per_channel_max; + if (amount_sat_greater(*our_funding, policy->per_channel_max)) + *our_funding = policy->per_channel_max; /* Is our_funding more than we have available? if so * set to max available */ @@ -259,7 +261,7 @@ calculate_our_funding(struct funder_policy policy, /* Is our_funding less than our per-channel minimum? * if so, don't fund */ - if (amount_sat_less(*our_funding, policy.per_channel_min)) { + if (amount_sat_less(*our_funding, policy->per_channel_min)) { *our_funding = AMOUNT_SAT(0); return tal_fmt(tmpctx, "Can't meet our min channel requirement." " our_funding %s," @@ -267,7 +269,7 @@ calculate_our_funding(struct funder_policy policy, type_to_string(tmpctx, struct amount_sat, our_funding), type_to_string(tmpctx, struct amount_sat, - &policy.per_channel_min)); + &policy->per_channel_min)); } return NULL; diff --git a/plugins/funder_policy.h b/plugins/funder_policy.h index 9c7bd9ef6232..aa97ef4cf828 100644 --- a/plugins/funder_policy.h +++ b/plugins/funder_policy.h @@ -55,8 +55,9 @@ struct funder_policy { u32 fund_probability; }; -struct funder_policy -new_funder_policy(enum funder_opt opt, +struct funder_policy * +new_funder_policy(const tal_t *ctx, + enum funder_opt opt, u64 policy_mod, struct amount_sat min_their_funding, struct amount_sat max_their_funding, @@ -67,14 +68,15 @@ new_funder_policy(enum funder_opt opt, u32 fund_probability); /* Get a new funder_policy, set to the defaults */ -struct funder_policy -default_funder_policy(enum funder_opt policy, +struct funder_policy * +default_funder_policy(const tal_t *ctx, + enum funder_opt policy, u64 policy_mod); /* Given the policy and this request's details, figure * out how much we should contribute to this channel */ const char * -calculate_our_funding(struct funder_policy policy, +calculate_our_funding(struct funder_policy *policy, struct node_id id, struct amount_sat their_funding, struct amount_sat available_funds, @@ -86,7 +88,7 @@ const char *funder_opt_name(enum funder_opt opt); /* Get a (short, for now) description of the provided policy */ const char *funder_policy_desc(const tal_t *ctx, - const struct funder_policy policy); + const struct funder_policy *policy); /* Convert a cmdline option to a funding_opt */ char *funding_option(const char *arg, enum funder_opt *opt); diff --git a/plugins/test/run-funder_policy.c b/plugins/test/run-funder_policy.c index b397f70a1dc0..a61ca864a033 100644 --- a/plugins/test/run-funder_policy.c +++ b/plugins/test/run-funder_policy.c @@ -376,7 +376,7 @@ static void check_fuzzing(struct test_case fuzzcase) memset(&id, 2, sizeof(struct node_id)); for (size_t i = 0; i < 100; i++) { - calculate_our_funding(fuzzcase.policy, id, + calculate_our_funding(&fuzzcase.policy, id, fuzzcase.their_funds, fuzzcase.available_funds, fuzzcase.channel_max, @@ -393,7 +393,7 @@ static void check_fuzzing(struct test_case fuzzcase) int main(int argc, const char *argv[]) { - struct funder_policy policy; + struct funder_policy *policy; struct node_id id; struct amount_sat empty = AMOUNT_SAT(0), our_funds; bool ok = true; @@ -406,7 +406,7 @@ int main(int argc, const char *argv[]) memset(&id, 2, sizeof(struct node_id)); /* Check the default funder policy, at fixed (0msat) */ - policy = default_funder_policy(FIXED, 0); + policy = default_funder_policy(tmpctx, FIXED, 0); err = calculate_our_funding(policy, id, AMOUNT_SAT(50000), @@ -417,14 +417,14 @@ int main(int argc, const char *argv[]) assert(!err); for (i = 0; i < ARRAY_SIZE(cases); i++) { - err = calculate_our_funding(cases[i].policy, id, + err = calculate_our_funding(&cases[i].policy, id, cases[i].their_funds, cases[i].available_funds, cases[i].channel_max, &our_funds); if (!amount_sat_eq(cases[i].exp_our_funds, our_funds)) { fprintf(stderr, "FAIL policy: %s. expected %s, got %s\n", - funder_policy_desc(NULL, cases[i].policy), + funder_policy_desc(NULL, &cases[i].policy), type_to_string(NULL, struct amount_sat, &cases[i].exp_our_funds), type_to_string(NULL, struct amount_sat, @@ -434,7 +434,7 @@ int main(int argc, const char *argv[]) if (cases[i].expect_err != (err != NULL)) { fprintf(stderr, "FAIL policy: %s. expected %serr," " got %s\n", - funder_policy_desc(NULL, cases[i].policy), + funder_policy_desc(NULL, &cases[i].policy), cases[i].expect_err ? "" : "no ", err ? err : "no err"); ok = false; @@ -450,7 +450,7 @@ int main(int argc, const char *argv[]) flipcase.policy.fund_probability = flips; for (i = 0; i < 100 * flips; i++) { - calculate_our_funding(flipcase.policy, id, + calculate_our_funding(&flipcase.policy, id, flipcase.their_funds, flipcase.available_funds, flipcase.channel_max, From d7e5933cdb86d88cbd1ca864d8696c500c698025 Mon Sep 17 00:00:00 2001 From: niftynei Date: Wed, 26 May 2021 18:13:08 -0500 Subject: [PATCH 10/56] funder-liqudity-ads: support options + setliquidity ad Implement support for liquidity ads in `funder` plugin. We set the command line options for the leases, as well as sending the updated ads to lightningd (who then passes them through to gossipd) --- plugins/Makefile | 3 +- plugins/funder.c | 370 +++++++++++++++++++++++++++++++++++----- plugins/funder_policy.c | 37 +++- plugins/funder_policy.h | 17 +- 4 files changed, 380 insertions(+), 47 deletions(-) diff --git a/plugins/Makefile b/plugins/Makefile index 410a2a7be9e6..e315a9fbbca7 100644 --- a/plugins/Makefile +++ b/plugins/Makefile @@ -113,6 +113,7 @@ PLUGIN_COMMON_OBJS := \ common/json_helpers.o \ common/json_stream.o \ common/json_tok.o \ + common/lease_rates.o \ common/memleak.o \ common/node_id.o \ common/param.o \ @@ -142,7 +143,7 @@ plugins/bcli: bitcoin/chainparams.o $(PLUGIN_BCLI_OBJS) $(PLUGIN_LIB_OBJS) $(PLU plugins/keysend: bitcoin/chainparams.o wire/tlvstream.o wire/onion$(EXP)_wiregen.o $(PLUGIN_KEYSEND_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_PAY_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS) common/gossmap.o common/fp16.o common/route.o common/dijkstra.o $(PLUGIN_KEYSEND_OBJS): $(PLUGIN_PAY_LIB_HEADER) -plugins/spenderp: bitcoin/chainparams.o bitcoin/psbt.o common/psbt_open.o $(PLUGIN_SPENDER_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS) +plugins/spenderp: bitcoin/block.o bitcoin/chainparams.o bitcoin/preimage.o bitcoin/psbt.o common/psbt_open.o wire/peer${EXP}_wiregen.o $(PLUGIN_SPENDER_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS) plugins/offers: bitcoin/chainparams.o $(PLUGIN_OFFERS_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_OBJS) common/bolt12.o common/bolt12_merkle.o common/bolt11_json.o common/iso4217.o $(WIRE_OBJS) bitcoin/block.o common/channel_id.o bitcoin/preimage.o $(JSMN_OBJS) $(CCAN_OBJS) diff --git a/plugins/funder.c b/plugins/funder.c index fc910d23ae39..7259334fc62d 100644 --- a/plugins/funder.c +++ b/plugins/funder.c @@ -10,18 +10,21 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include #include #include #include +#include /* In-progress channel opens */ static struct list_head pending_opens; @@ -679,8 +682,8 @@ static void json_channel_open_failed(struct command *cmd, unreserve_psbt(open); } -static void policy_to_json(struct json_stream *stream, - struct funder_policy *policy) +static void json_add_policy(struct json_stream *stream, + struct funder_policy *policy) { json_add_string(stream, "summary", funder_policy_desc(stream, current_policy)); @@ -699,6 +702,9 @@ static void policy_to_json(struct json_stream *stream, policy->reserve_tank); json_add_num(stream, "fuzz_percent", policy->fuzz_factor); json_add_num(stream, "fund_probability", policy->fund_probability); + + if (policy->rates) + json_add_lease_rates(stream, policy->rates); } static struct command_result * @@ -744,75 +750,252 @@ param_policy_mod(struct command *cmd, const char *name, return NULL; } +static struct command_result * +parse_lease_rates(struct command *cmd, const char *buffer, + const jsmntok_t *tok, + struct funder_policy *policy, + struct funder_policy *current_policy, + u32 *lease_fee_basis, + struct amount_sat *lease_fee_sats, + u32 *funding_weight, + u32 *chan_fee_ppt, + struct amount_msat *chan_fee_msats) + +{ + /* If there's already rates set, we start with those */ + if (!lease_rates_empty(current_policy->rates)) + policy->rates = tal_dup(policy, struct lease_rates, + current_policy->rates); + else if (lease_fee_basis + || lease_fee_sats + || funding_weight + || chan_fee_ppt + || chan_fee_msats) + policy->rates = default_lease_rates(policy); + else + policy->rates = NULL; + + + if (lease_fee_basis) { + policy->rates->lease_fee_basis = *lease_fee_basis; + + /* Check for overflow */ + if (policy->rates->lease_fee_basis != *lease_fee_basis) + return command_fail_badparam(cmd, "lease_fee_basis", + buffer, tok, "overflow"); + } + + if (lease_fee_sats) { + policy->rates->lease_fee_base_sat + = lease_fee_sats->satoshis; /* Raw: conversion */ + if (policy->rates->lease_fee_base_sat + != lease_fee_sats->satoshis) /* Raw: comparison */ + return command_fail_badparam(cmd, "lease_fee_base_msat", + buffer, tok, "overflow"); + } + + if (funding_weight) { + policy->rates->funding_weight = *funding_weight; + + /* Check for overflow */ + if (policy->rates->funding_weight != *funding_weight) + return command_fail_badparam(cmd, "funding_weight", + buffer, tok, "overflow"); + } + + if (chan_fee_ppt) { + policy->rates->channel_fee_max_proportional_thousandths + = *chan_fee_ppt; + + /* Check for overflow */ + if (policy->rates->channel_fee_max_proportional_thousandths + != *chan_fee_ppt) + return command_fail_badparam(cmd, "channel_fee_max_proportional_thousandths", + buffer, tok, "overflow"); + } + + if (chan_fee_msats) { + policy->rates->channel_fee_max_base_msat + = chan_fee_msats->millisatoshis; /* Raw: conversion */ + if (policy->rates->channel_fee_max_base_msat + != chan_fee_msats->millisatoshis) /* Raw: comparison */ + return command_fail_badparam(cmd, + "channel_fee_max_base_msat", + buffer, tok, "overflow"); + } + + return NULL; +} + +static struct command_result * +leaserates_set(struct command *cmd, const char *buf, + const jsmntok_t *result, + struct funder_policy *policy) +{ + struct json_stream *res; + + /* Ok, we updated lightningd with latest info */ + res = jsonrpc_stream_success(cmd); + json_add_policy(res, policy); + return command_finished(cmd, res); +} + static struct command_result * json_funderupdate(struct command *cmd, const char *buf, const jsmntok_t *params) { - struct json_stream *res; struct amount_sat *min_their_funding, *max_their_funding, *per_channel_min, *per_channel_max, - *reserve_tank; - u32 *fuzz_factor, *fund_probability; + *reserve_tank, *lease_fee_sats; + struct amount_msat *channel_fee_msats; + u32 *fuzz_factor, *fund_probability, *chan_fee_ppt, + *lease_fee_basis, *funding_weight; u64 *mod; + bool *leases_only; enum funder_opt *opt; + const struct out_req *req; const char *err; - struct funder_policy *policy = current_policy; + struct command_result *res; + + struct funder_policy *policy = tal(tal_parent(current_policy), + struct funder_policy); if (!param(cmd, buf, params, - p_opt("policy", param_funder_opt, &opt), - p_opt("policy_mod", param_policy_mod, &mod), - p_opt("min_their_funding", param_sat, &min_their_funding), - p_opt("max_their_funding", param_sat, &max_their_funding), - p_opt("per_channel_min", param_sat, &per_channel_min), - p_opt("per_channel_max", param_sat, &per_channel_max), - p_opt("reserve_tank", param_sat, &reserve_tank), - p_opt("fuzz_percent", param_number, &fuzz_factor), - p_opt("fund_probability", param_number, &fund_probability), + p_opt_def("policy", param_funder_opt, &opt, + current_policy->opt), + p_opt_def("policy_mod", param_policy_mod, &mod, + current_policy->mod), + p_opt_def("leases_only", param_bool, &leases_only, + current_policy->leases_only), + p_opt_def("min_their_funding", param_sat, + &min_their_funding, + current_policy->min_their_funding), + p_opt_def("max_their_funding", param_sat, + &max_their_funding, + current_policy->max_their_funding), + p_opt_def("per_channel_min", param_sat, + &per_channel_min, + current_policy->per_channel_min), + p_opt_def("per_channel_max", param_sat, + &per_channel_max, + current_policy->per_channel_max), + p_opt_def("reserve_tank", param_sat, &reserve_tank, + current_policy->reserve_tank), + p_opt_def("fuzz_percent", param_number, + &fuzz_factor, + current_policy->fuzz_factor), + p_opt_def("fund_probability", param_number, + &fund_probability, + current_policy->fund_probability), + p_opt("lease_fee_base_msat", param_sat, &lease_fee_sats), + p_opt("lease_fee_basis", param_number, &lease_fee_basis), + p_opt("funding_weight", param_number, &funding_weight), + p_opt("channel_fee_max_base_msat", param_msat, + &channel_fee_msats), + p_opt("channel_fee_max_proportional_thousandths", + param_number, &chan_fee_ppt), NULL)) return command_param_failed(); - if (opt) - policy->opt = *opt; - if (mod) - policy->mod = *mod; - if (min_their_funding) - policy->min_their_funding = *min_their_funding; - if (max_their_funding) - policy->max_their_funding = *max_their_funding; - if (per_channel_min) - policy->per_channel_min = *per_channel_min; - if (per_channel_max) - policy->per_channel_max = *per_channel_max; - if (reserve_tank) - policy->reserve_tank = *reserve_tank; - if (fuzz_factor) - policy->fuzz_factor = *fuzz_factor; - if (fund_probability) - policy->fund_probability = *fund_probability; + policy->opt = *opt; + policy->mod = *mod; + policy->min_their_funding = *min_their_funding; + policy->max_their_funding = *max_their_funding; + policy->per_channel_min = *per_channel_min; + policy->per_channel_max = *per_channel_max; + policy->reserve_tank = *reserve_tank; + policy->fuzz_factor = *fuzz_factor; + policy->fund_probability = *fund_probability; + policy->leases_only = *leases_only; + + res = parse_lease_rates(cmd, buf, params, + policy, current_policy, + lease_fee_basis, + lease_fee_sats, + funding_weight, + chan_fee_ppt, + channel_fee_msats); + if (res) + return res; err = funder_check_policy(policy); - if (err) + if (err) { + tal_free(policy); return command_done_err(cmd, JSONRPC2_INVALID_PARAMS, err, NULL); + } + tal_free(current_policy); current_policy = policy; - res = jsonrpc_stream_success(cmd); - policy_to_json(res, current_policy); - return command_finished(cmd, res); + + /* Update lightningd, also */ + req = jsonrpc_request_start(cmd->plugin, cmd, + "setleaserates", + &leaserates_set, + &forward_error, + current_policy); + + if (current_policy->rates) + json_add_lease_rates(req->js, current_policy->rates); + else { + /* Add empty rates to turn off */ + struct lease_rates rates; + memset(&rates, 0, sizeof(rates)); + json_add_lease_rates(req->js, &rates); + } + + return send_outreq(cmd->plugin, req); } -static const struct plugin_command commands[] = { { +static const struct plugin_command commands[] = { + { "funderupdate", - "channels", - "Update configuration for dual-funding offer", - "Update current funder settings. Modifies how node" - " reacts to incoming channel open requests. Responds with list" + "liquidity", + "Configuration for dual-funding settings.", + "Update current settings. Modifies how node reacts to" + " incoming channel open requests. Responds with list" " of current configs.", json_funderupdate - } + }, }; +static void tell_lightningd_lease_rates(struct plugin *p, + struct lease_rates *rates) +{ + struct json_out *jout; + struct amount_sat val; + struct amount_msat mval; + + /* Tell lightningd with our lease rates*/ + jout = json_out_new(NULL); + json_out_start(jout, NULL, '{'); + + val = amount_sat(rates->lease_fee_base_sat); + json_out_addstr(jout, "lease_fee_base_msat", + type_to_string(tmpctx, struct amount_sat, &val)); + json_out_add(jout, "lease_fee_basis", false, + "%d", rates->lease_fee_basis); + + json_out_add(jout, "funding_weight", false, + "%d", rates->funding_weight); + + mval = amount_msat(rates->channel_fee_max_base_msat); + json_out_addstr(jout, "channel_fee_max_base_msat", + type_to_string(tmpctx, struct amount_msat, &mval)); + json_out_add(jout, "channel_fee_max_proportional_thousandths", false, + "%d", rates->channel_fee_max_proportional_thousandths); + + json_out_end(jout, '}'); + json_out_finished(jout); + + rpc_scan(p, "setleaserates", take(jout), + /* Unused */ + "{lease_fee_base_msat:%}", + JSON_SCAN(json_to_sat, &val)); + +} + static const char *init(struct plugin *p, const char *b, const jsmntok_t *t) { const char *err; @@ -823,6 +1006,9 @@ static const char *init(struct plugin *p, const char *b, const jsmntok_t *t) if (err) plugin_err(p, "Invalid parameter combination: %s", err); + if (current_policy->rates) + tell_lightningd_lease_rates(p, current_policy->rates); + return NULL; } @@ -856,6 +1042,33 @@ const struct plugin_notification notifs[] = { }, }; +static char *option_channel_base(const char *arg, struct funder_policy *policy) +{ + struct amount_msat amt; + + if (!parse_amount_msat(&amt, arg, strlen(arg))) + return tal_fmt(NULL, "Unable to parse amount '%s'", arg); + + if (!policy->rates) + policy->rates = default_lease_rates(policy); + + policy->rates->channel_fee_max_base_msat = amt.millisatoshis; /* Raw: conversion */ + + if (policy->rates->channel_fee_max_base_msat != amt.millisatoshis) /* Raw: comparison */ + return tal_fmt(NULL, "channel_fee_max_base_msat overflowed"); + + return NULL; +} + +static char * +option_channel_fee_proportional_thousandths_max(const char *arg, + struct funder_policy *policy) +{ + if (!policy->rates) + policy->rates = default_lease_rates(policy); + return u16_option(arg, &policy->rates->channel_fee_max_proportional_thousandths); +} + static char *amount_option(const char *arg, struct amount_sat *amt) { if (!parse_amount_sat(amt, arg, strlen(arg))) @@ -864,6 +1077,41 @@ static char *amount_option(const char *arg, struct amount_sat *amt) return NULL; } +static char *option_lease_fee_base(const char *arg, + struct funder_policy *policy) +{ + struct amount_sat amt; + char *err; + if (!policy->rates) + policy->rates = default_lease_rates(policy); + + err = amount_option(arg, &amt); + if (err) + return err; + + policy->rates->lease_fee_base_sat = amt.satoshis; /* Raw: conversion */ + if (policy->rates->lease_fee_base_sat != amt.satoshis) /* Raw: comparison */ + return tal_fmt(NULL, "lease_fee_base_sat overflowed"); + + return NULL; +} + +static char *option_lease_fee_basis(const char *arg, + struct funder_policy *policy) +{ + if (!policy->rates) + policy->rates = default_lease_rates(policy); + return u16_option(arg, &policy->rates->lease_fee_basis); +} + +static char *option_lease_weight_max(const char *arg, + struct funder_policy *policy) +{ + if (!policy->rates) + policy->rates = default_lease_rates(policy); + return u16_option(arg, &policy->rates->funding_weight); +} + static char *amount_sat_or_u64_option(const char *arg, u64 *amt) { struct amount_sat sats; @@ -953,6 +1201,42 @@ int main(int argc, char **argv) " disable dual-funding", u32_option, ¤t_policy->fund_probability), + plugin_option("funder-lease-requests-only", + "bool", + "Only fund lease requests. Defaults to" + " true if channel lease rates are" + " being advertised", + bool_option, + ¤t_policy->leases_only), + plugin_option("lease-fee-base-msat", + "string", + "Channel lease rates, base fee for leased" + " funds, in satoshi.", + option_lease_fee_base, current_policy), + plugin_option("lease-fee-basis", + "int", + "Channel lease rates, basis charged" + " for leased funds (per 10,000 satoshi.)", + option_lease_fee_basis, current_policy), + plugin_option("lease-funding-weight", + "int", + "Channel lease rates, weight" + " we'll ask opening peer to pay for in" + " funding transaction", + option_lease_weight_max, current_policy), + plugin_option("channel-fee-max-base-msat", + "string", + "Channel lease rates, maximum channel" + " fee base we'll charge for funds" + " routed through a leased channel.", + option_channel_base, current_policy), + plugin_option("channel-fee-max-proportional-thousandths", + "int", + "Channel lease rates, maximum" + " proportional fee (in thousandths, or ppt)" + " we'll charge for funds routed through a" + " leased channel. Note: 1ppt = 1,000ppm", + option_channel_fee_proportional_thousandths_max, current_policy), NULL); tal_free(owner); diff --git a/plugins/funder_policy.c b/plugins/funder_policy.c index 69dabf9bd437..4ded29088c44 100644 --- a/plugins/funder_policy.c +++ b/plugins/funder_policy.c @@ -1,5 +1,7 @@ #include +#include #include +#include #include #include #include @@ -59,7 +61,9 @@ new_funder_policy(const tal_t *ctx, struct amount_sat per_channel_max, u32 fuzz_factor, struct amount_sat reserve_tank, - u32 fund_probability) + u32 fund_probability, + bool leases_only, + struct lease_rates *rates) { struct funder_policy *policy = tal(ctx, struct funder_policy); @@ -72,6 +76,8 @@ new_funder_policy(const tal_t *ctx, policy->fuzz_factor = fuzz_factor; policy->reserve_tank = reserve_tank; policy->fund_probability = fund_probability; + policy->leases_only = leases_only; + policy->rates = rates; return policy; } @@ -88,7 +94,34 @@ default_funder_policy(const tal_t *ctx, AMOUNT_SAT(UINT_MAX), 0, /* fuzz_factor */ AMOUNT_SAT(0), /* reserve_tank */ - 100); + 100, + /* Defaults to true iif we're advertising + * offers */ + false, + NULL); +} + +struct lease_rates * +default_lease_rates(const tal_t *ctx) +{ + struct lease_rates *rates = tal(ctx, struct lease_rates); + + /* Default basis is .65%, (7.8% APR) */ + rates->lease_fee_basis = 65; + /* 2000sat base rate */ + rates->lease_fee_base_sat = 2000; + /* Max of 100,000ppm (10%) */ + rates->channel_fee_max_proportional_thousandths = 100; + /* Max of 5000sat */ + rates->channel_fee_max_base_msat = 5000000; + + /* Let's set our default max weight to two inputs + an output + * (use helpers b/c elements) */ + rates->funding_weight + = 2 * bitcoin_tx_simple_input_weight(false) + + bitcoin_tx_output_weight(BITCOIN_SCRIPTPUBKEY_P2WPKH_LEN); + + return rates; } char *funder_check_policy(const struct funder_policy *policy) diff --git a/plugins/funder_policy.h b/plugins/funder_policy.h index aa97ef4cf828..dfb12e19977a 100644 --- a/plugins/funder_policy.h +++ b/plugins/funder_policy.h @@ -2,7 +2,9 @@ #define LIGHTNING_PLUGINS_FUNDER_POLICY_H #include "config.h" #include +#include +struct lease_rates; struct node_id; /* Policy Options */ @@ -53,6 +55,13 @@ struct funder_policy { /* Percent of open offers we'll consider funding. */ u32 fund_probability; + + /* If we're advertising liquidity, only + * provide funds for lease requests */ + bool leases_only; + + /* Rates we're currently charging for channel leases */ + struct lease_rates *rates; }; struct funder_policy * @@ -65,7 +74,9 @@ new_funder_policy(const tal_t *ctx, struct amount_sat per_channel_max, u32 fuzz_factor, struct amount_sat reserve_tank, - u32 fund_probability); + u32 fund_probability, + bool leases_only, + struct lease_rates *rates); /* Get a new funder_policy, set to the defaults */ struct funder_policy * @@ -73,6 +84,10 @@ default_funder_policy(const tal_t *ctx, enum funder_opt policy, u64 policy_mod); +/* Defaults to use for the lease_rates */ +struct lease_rates * +default_lease_rates(const tal_t *ctx); + /* Given the policy and this request's details, figure * out how much we should contribute to this channel */ const char * From 14df559f6fa9922d93377b1c595283d4e849e629 Mon Sep 17 00:00:00 2001 From: niftynei Date: Sat, 29 May 2021 14:01:19 -0500 Subject: [PATCH 11/56] contrib: offer a liquidity-ad lease in developer mode --- contrib/startup_regtest.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contrib/startup_regtest.sh b/contrib/startup_regtest.sh index 2f9640c24762..996e20fe9dfe 100755 --- a/contrib/startup_regtest.sh +++ b/contrib/startup_regtest.sh @@ -101,6 +101,8 @@ start_nodes() { funder-min-their-funding=10000 funder-per-channel-max=100000 funder-fuzz-percent=0 + lease-fee-base-msat=2sat + lease-fee-basis=50 EOF fi From f9570fe1604325e72e76b79fb9f907935f2b2638 Mon Sep 17 00:00:00 2001 From: niftynei Date: Wed, 26 May 2021 18:16:07 -0500 Subject: [PATCH 12/56] tests: add test for setting/updating node announce Make sure everything updates/flows through as expected. --- tests/test_gossip.py | 79 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/tests/test_gossip.py b/tests/test_gossip.py index d1d77a0e4719..ec0a995f9dfb 100644 --- a/tests/test_gossip.py +++ b/tests/test_gossip.py @@ -928,6 +928,85 @@ def test_gossip_addresses(node_factory, bitcoind): ] +@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') +@pytest.mark.developer("needs dev-fast-gossip") +@pytest.mark.openchannel('v2') +def test_gossip_lease_rates(node_factory, bitcoind): + lease_opts = {'lease-fee-basis': 50, + 'lease-fee-base-msat': '2000msat', + 'channel-fee-max-base-msat': '500sat', + 'channel-fee-max-proportional-thousandths': 200} + l1, l2 = node_factory.get_nodes(2, opts=[lease_opts, {}]) + + # These logs happen during startup, start looking from the beginning + l1.daemon.logsearch_start = 0 + l2.daemon.logsearch_start = 0 + + rates = l1.rpc.call('funderupdate') + assert rates['channel_fee_max_base_msat'] == Millisatoshi('500000msat') + assert rates['channel_fee_max_proportional_thousandths'] == 200 + assert rates['funding_weight'] == 666 # Default on regtest + assert rates['lease_fee_base_msat'] == Millisatoshi('2000msat') + assert rates['lease_fee_basis'] == 50 + + rates = l2.rpc.call('funderupdate') + assert 'channel_fee_max_base_msat' not in rates + assert 'channel_fee_max_proportional_thousandths' not in rates + assert 'funding_weight' not in rates + assert 'lease_fee_base_msat' not in rates + assert 'lease_fee_basis' not in rates + + # Open a channel, check that the node_announcements + # include offer details, as expected + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + l1.fundchannel(l2, 10**6) + + # Announce depth is ALWAYS 6 blocks + bitcoind.generate_block(5) + + l2.daemon.wait_for_log('Received node_announcement for node {}' + .format(l1.info['id'])) + l1.daemon.wait_for_log('Received node_announcement for node {}' + .format(l2.info['id'])) + + l2_nodeinfo = only_one(l1.rpc.listnodes(l2.info['id'])['nodes']) + l1_nodeinfo = only_one(l2.rpc.listnodes(l1.info['id'])['nodes']) + + assert 'option_will_fund' not in l2_nodeinfo + rates = l1_nodeinfo['option_will_fund'] + assert rates['channel_fee_max_base_msat'] == Millisatoshi('500000msat') + assert rates['channel_fee_max_proportional_thousandths'] == 200 + assert rates['funding_weight'] == 666 # Default on regtest + assert rates['lease_fee_base_msat'] == Millisatoshi('2000msat') + assert rates['lease_fee_basis'] == 50 + + # Update the node announce (set new on l2, turn off l1) + # (Turn off by setting everything to zero) + l1.rpc.call('funderupdate', {'channel_fee_max_base_msat': '0msat', + 'channel_fee_max_proportional_thousandths': 0, + 'funding_weight': 0, + 'lease_fee_base_msat': '0msat', + 'lease_fee_basis': 0}) + l2.rpc.call('funderupdate', {'channel_fee_max_base_msat': '30000msat', + 'channel_fee_max_proportional_thousandths': 100, + 'lease_fee_base_msat': '400000msat', + 'lease_fee_basis': 20}) + + l1.daemon.wait_for_log('Received node_announcement for node {}'.format(l2.info['id'])) + l2.daemon.wait_for_log('Received node_announcement for node {}'.format(l1.info['id'])) + + l2_nodeinfo = only_one(l1.rpc.listnodes(l2.info['id'])['nodes']) + l1_nodeinfo = only_one(l2.rpc.listnodes(l1.info['id'])['nodes']) + + assert 'option_will_fund' not in l1_nodeinfo + rates = l2_nodeinfo['option_will_fund'] + assert rates['channel_fee_max_base_msat'] == Millisatoshi('30000msat') + assert rates['channel_fee_max_proportional_thousandths'] == 100 + assert rates['funding_weight'] == 666 # Default on regtest + assert rates['lease_fee_base_msat'] == Millisatoshi('400000msat') + assert rates['lease_fee_basis'] == 20 + + def test_gossip_store_load(node_factory): """Make sure we can read canned gossip store""" l1 = node_factory.get_node(start=False) From 3431dbaf3b4581d4d4f2e367b88ee6bad152e874 Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 8 Jun 2021 15:32:04 -0500 Subject: [PATCH 13/56] psbt: promote weight calculation methods to 'library' Will re-use these for the psbt weight payment calc later --- bitcoin/psbt.c | 24 ++++++++++++++++++++++++ bitcoin/psbt.h | 4 ++++ openingd/dualopend.c | 26 -------------------------- 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/bitcoin/psbt.c b/bitcoin/psbt.c index df76d4e6cd34..00b88cd307ec 100644 --- a/bitcoin/psbt.c +++ b/bitcoin/psbt.c @@ -848,3 +848,27 @@ struct amount_sat psbt_compute_fee(const struct wally_psbt *psbt) return fee; } + +size_t psbt_input_weight(const struct wally_psbt *psbt, size_t in) +{ + size_t weight; + + /* txid + txout + sequence */ + weight = (32 + 4 + 4) * 4; + weight += + (psbt->inputs[in].redeem_script_len + + (varint_t) varint_size(psbt->inputs[in].redeem_script_len)) * 4; + + /* BOLT-f53ca2301232db780843e894f55d95d512f297f9 #3: + * + * The minimum witness weight for an input is 110. + */ + weight += 110; + return weight; +} + +size_t psbt_output_weight(const struct wally_psbt *psbt, size_t outnum) +{ + return (8 + psbt->tx->outputs[outnum].script_len + + varint_size(psbt->tx->outputs[outnum].script_len)) * 4; +} diff --git a/bitcoin/psbt.h b/bitcoin/psbt.h index e1fa9b4068e8..4d5351456d8a 100644 --- a/bitcoin/psbt.h +++ b/bitcoin/psbt.h @@ -272,4 +272,8 @@ struct wally_psbt *psbt_from_bytes(const tal_t *ctx, const u8 *bytes, void towire_wally_psbt(u8 **pptr, const struct wally_psbt *psbt); struct wally_psbt *fromwire_wally_psbt(const tal_t *ctx, const u8 **cursor, size_t *max); + +/* Calculate the weight of a psbt input or output */ +size_t psbt_input_weight(const struct wally_psbt *psbt, size_t in); +size_t psbt_output_weight(const struct wally_psbt *psbt, size_t outnum); #endif /* LIGHTNING_BITCOIN_PSBT_H */ diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 7d8dadbb589f..06c2f9a7bb97 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -512,32 +512,6 @@ static bool is_openers(const struct wally_map *unknowns) return serial_id % 2 == TX_INITIATOR; } -static size_t psbt_input_weight(struct wally_psbt *psbt, - size_t in) -{ - size_t weight; - - /* txid + txout + sequence */ - weight = (32 + 4 + 4) * 4; - weight += - (psbt->inputs[in].redeem_script_len + - (varint_t) varint_size(psbt->inputs[in].redeem_script_len)) * 4; - - /* BOLT-f53ca2301232db780843e894f55d95d512f297f9 #3: - * - * The minimum witness weight for an input is 110. - */ - weight += 110; - return weight; -} - -static size_t psbt_output_weight(struct wally_psbt *psbt, - size_t outnum) -{ - return (8 + psbt->tx->outputs[outnum].script_len + - varint_size(psbt->tx->outputs[outnum].script_len)) * 4; -} - static bool find_txout(struct wally_psbt *psbt, const u8 *wscript, u16 *funding_txout) { for (size_t i = 0; i < psbt->num_outputs; i++) { From 1d92dbb09885ce9497a8223989ec24d0c364c41f Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 8 Jun 2021 15:37:49 -0500 Subject: [PATCH 14/56] amount: add 'is_zero' helper convenience, mostly --- common/amount.c | 5 +++++ common/amount.h | 3 +++ lightningd/dual_open_control.c | 8 ++++---- plugins/funder.c | 2 +- plugins/funder_policy.c | 6 +++--- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/common/amount.c b/common/amount.c index 3736d2913216..ddea6569c4f9 100644 --- a/common/amount.c +++ b/common/amount.c @@ -357,6 +357,11 @@ bool amount_sat_eq(struct amount_sat a, struct amount_sat b) return a.satoshis == b.satoshis; } +bool amount_sat_zero(struct amount_sat a) +{ + return a.satoshis == 0; +} + bool amount_msat_eq(struct amount_msat a, struct amount_msat b) { return a.millisatoshis == b.millisatoshis; diff --git a/common/amount.h b/common/amount.h index 58df61c5c32b..46d95d99de03 100644 --- a/common/amount.h +++ b/common/amount.h @@ -94,6 +94,9 @@ struct amount_sat amount_sat_div(struct amount_sat sat, u64 div); bool amount_sat_eq(struct amount_sat a, struct amount_sat b); bool amount_msat_eq(struct amount_msat a, struct amount_msat b); +/* Is a zero? */ +bool amount_sat_zero(struct amount_sat a); + /* Is a > b? */ bool amount_sat_greater(struct amount_sat a, struct amount_sat b); bool amount_msat_greater(struct amount_msat a, struct amount_msat b); diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index ac9e1f6effea..1fa554eb996b 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -619,11 +619,11 @@ rbf_channel_hook_deserialize(struct rbf_channel_payload *payload, fatal("Plugin failed to supply our_funding_msat field"); if (payload->psbt - && amount_sat_eq(payload->our_funding, AMOUNT_SAT(0))) + && amount_sat_zero(payload->our_funding)) fatal("Plugin failed to supply our_funding_msat field"); if (!payload->psbt && - !amount_sat_eq(payload->our_funding, AMOUNT_SAT(0))) { + !amount_sat_zero(payload->our_funding)) { log_broken(channel->log, "`our_funding_msat` returned" " but no `psbt` present. %.*s", @@ -777,11 +777,11 @@ openchannel2_hook_deserialize(struct openchannel2_payload *payload, fatal("Plugin failed to supply our_funding_msat field"); if (payload->psbt - && amount_sat_eq(payload->accepter_funding, AMOUNT_SAT(0))) + && amount_sat_zero(payload->accepter_funding)) fatal("Plugin failed to supply our_funding_msat field"); if (!payload->psbt - && !amount_sat_eq(payload->accepter_funding, AMOUNT_SAT(0))) { + && !amount_sat_zero(payload->accepter_funding)) { /* Gotta give a PSBT if you set the accepter_funding amount */ /* Let dualopend know we've failed */ payload->err_msg = "Client error. Unable to continue"; diff --git a/plugins/funder.c b/plugins/funder.c index 7259334fc62d..891154dc63d4 100644 --- a/plugins/funder.c +++ b/plugins/funder.c @@ -427,7 +427,7 @@ listfunds_success(struct command *cmd, &info->our_funding), funding_err ? funding_err : ""); - if (amount_sat_eq(info->our_funding, AMOUNT_SAT(0))) + if (amount_sat_zero(info->our_funding)) return command_hook_success(cmd); plugin_log(cmd->plugin, LOG_DBG, diff --git a/plugins/funder_policy.c b/plugins/funder_policy.c index 4ded29088c44..428b4c42f809 100644 --- a/plugins/funder_policy.c +++ b/plugins/funder_policy.c @@ -220,7 +220,7 @@ calculate_our_funding(struct funder_policy *policy, /* Figure out amount of actual headroom we have */ if (!amount_sat_sub(&avail_channel_space, channel_max, their_funding) - || amount_sat_eq(avail_channel_space, AMOUNT_SAT(0))) { + || amount_sat_zero(avail_channel_space)) { *our_funding = AMOUNT_SAT(0); return tal_fmt(tmpctx, "No space available in channel." " channel_max %s, their_funding %s", @@ -234,7 +234,7 @@ calculate_our_funding(struct funder_policy *policy, * 'reserve_tank' */ if (!amount_sat_sub(&net_available_funds, available_funds, policy->reserve_tank) - || amount_sat_eq(net_available_funds, AMOUNT_SAT(0))) { + || amount_sat_zero(net_available_funds)) { *our_funding = AMOUNT_SAT(0); return tal_fmt(tmpctx, "Reserve tank too low." " available_funds %s, reserve_tank requires %s", @@ -272,7 +272,7 @@ calculate_our_funding(struct funder_policy *policy, *our_funding = apply_policy(policy, their_funding, available_funds); /* Don't return an 'error' if we're already at 0 */ - if (amount_sat_eq(*our_funding, AMOUNT_SAT(0))) + if (amount_sat_zero(*our_funding)) return NULL; /* our_funding is probably sane, so let's fuzz this amount a bit */ From c7f1e1a09aa2f965b05ea059a111ad39f17acf4a Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 8 Jun 2021 15:45:23 -0500 Subject: [PATCH 15/56] hsmd: method to sign liquidity ad offer When we accept a bid to create a channel lease, we send back a signature committing to our max channel lease amounts. --- hsmd/capabilities.h | 1 + hsmd/hsmd.c | 2 ++ hsmd/hsmd_wire.csv | 9 ++++++++ hsmd/hsmd_wiregen.c | 55 ++++++++++++++++++++++++++++++++++++++++++++- hsmd/hsmd_wiregen.h | 14 +++++++++++- hsmd/libhsmd.c | 54 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 133 insertions(+), 2 deletions(-) diff --git a/hsmd/capabilities.h b/hsmd/capabilities.h index 3a306e778a2a..a95177901a61 100644 --- a/hsmd/capabilities.h +++ b/hsmd/capabilities.h @@ -7,6 +7,7 @@ #define HSM_CAP_COMMITMENT_POINT 8 #define HSM_CAP_SIGN_REMOTE_TX 16 #define HSM_CAP_SIGN_CLOSING_TX 32 +#define HSM_CAP_SIGN_WILL_FUND_OFFER 64 #define HSM_CAP_MASTER 1024 #endif /* LIGHTNING_HSMD_CAPABILITIES_H */ diff --git a/hsmd/hsmd.c b/hsmd/hsmd.c index 28eafd153351..39642fc9c473 100644 --- a/hsmd/hsmd.c +++ b/hsmd/hsmd.c @@ -663,6 +663,7 @@ static struct io_plan *handle_client(struct io_conn *conn, struct client *c) case WIRE_HSMD_GET_CHANNEL_BASEPOINTS: case WIRE_HSMD_SIGN_INVOICE: case WIRE_HSMD_SIGN_MESSAGE: + case WIRE_HSMD_SIGN_OPTION_WILL_FUND_OFFER: case WIRE_HSMD_SIGN_BOLT12: case WIRE_HSMD_ECDH_REQ: case WIRE_HSMD_CHECK_FUTURE_SECRET: @@ -689,6 +690,7 @@ static struct io_plan *handle_client(struct io_conn *conn, struct client *c) case WIRE_HSMSTATUS_CLIENT_BAD_REQUEST: case WIRE_HSMD_SIGN_COMMITMENT_TX_REPLY: case WIRE_HSMD_SIGN_TX_REPLY: + case WIRE_HSMD_SIGN_OPTION_WILL_FUND_OFFER_REPLY: case WIRE_HSMD_GET_PER_COMMITMENT_POINT_REPLY: case WIRE_HSMD_CHECK_FUTURE_SECRET_REPLY: case WIRE_HSMD_GET_CHANNEL_BASEPOINTS_REPLY: diff --git a/hsmd/hsmd_wire.csv b/hsmd/hsmd_wire.csv index 86be49bb13d9..e6126bf9b84c 100644 --- a/hsmd/hsmd_wire.csv +++ b/hsmd/hsmd_wire.csv @@ -212,3 +212,12 @@ msgdata,hsmd_sign_bolt12,publictweak,u8,publictweaklen msgtype,hsmd_sign_bolt12_reply,125 msgdata,hsmd_sign_bolt12_reply,sig,bip340sig, +# Sign an option_will_fund offer hash +msgtype,hsmd_sign_option_will_fund_offer,26 +msgdata,hsmd_sign_option_will_fund_offer,funding_pubkey,pubkey, +msgdata,hsmd_sign_option_will_fund_offer,blockheight,u32, +msgdata,hsmd_sign_option_will_fund_offer,channel_fee_base_max_msat,u32, +msgdata,hsmd_sign_option_will_fund_offer,channel_fee_proportional_basis_max,u16, + +msgtype,hsmd_sign_option_will_fund_offer_reply,126 +msgdata,hsmd_sign_option_will_fund_offer_reply,rsig,secp256k1_ecdsa_signature, diff --git a/hsmd/hsmd_wiregen.c b/hsmd/hsmd_wiregen.c index 048a49a282d6..0007219f96e7 100644 --- a/hsmd/hsmd_wiregen.c +++ b/hsmd/hsmd_wiregen.c @@ -62,6 +62,8 @@ const char *hsmd_wire_name(int e) case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY_REPLY: return "WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY_REPLY"; case WIRE_HSMD_SIGN_BOLT12: return "WIRE_HSMD_SIGN_BOLT12"; case WIRE_HSMD_SIGN_BOLT12_REPLY: return "WIRE_HSMD_SIGN_BOLT12_REPLY"; + case WIRE_HSMD_SIGN_OPTION_WILL_FUND_OFFER: return "WIRE_HSMD_SIGN_OPTION_WILL_FUND_OFFER"; + case WIRE_HSMD_SIGN_OPTION_WILL_FUND_OFFER_REPLY: return "WIRE_HSMD_SIGN_OPTION_WILL_FUND_OFFER_REPLY"; } snprintf(invalidbuf, sizeof(invalidbuf), "INVALID %i", e); @@ -112,6 +114,8 @@ bool hsmd_wire_is_defined(u16 type) case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY_REPLY:; case WIRE_HSMD_SIGN_BOLT12:; case WIRE_HSMD_SIGN_BOLT12_REPLY:; + case WIRE_HSMD_SIGN_OPTION_WILL_FUND_OFFER:; + case WIRE_HSMD_SIGN_OPTION_WILL_FUND_OFFER_REPLY:; return true; } return false; @@ -1278,4 +1282,53 @@ bool fromwire_hsmd_sign_bolt12_reply(const void *p, struct bip340sig *sig) fromwire_bip340sig(&cursor, &plen, sig); return cursor != NULL; } -// SHA256STAMP:535c69a065c06a2e2ea151154ae83b53283d1c5b34e18b43a2c12c9444472548 + +/* WIRE: HSMD_SIGN_OPTION_WILL_FUND_OFFER */ +/* Sign an option_will_fund offer hash */ +u8 *towire_hsmd_sign_option_will_fund_offer(const tal_t *ctx, const struct pubkey *funding_pubkey, u32 blockheight, u32 channel_fee_base_max_msat, u16 channel_fee_proportional_basis_max) +{ + u8 *p = tal_arr(ctx, u8, 0); + + towire_u16(&p, WIRE_HSMD_SIGN_OPTION_WILL_FUND_OFFER); + towire_pubkey(&p, funding_pubkey); + towire_u32(&p, blockheight); + towire_u32(&p, channel_fee_base_max_msat); + towire_u16(&p, channel_fee_proportional_basis_max); + + return memcheck(p, tal_count(p)); +} +bool fromwire_hsmd_sign_option_will_fund_offer(const void *p, struct pubkey *funding_pubkey, u32 *blockheight, u32 *channel_fee_base_max_msat, u16 *channel_fee_proportional_basis_max) +{ + const u8 *cursor = p; + size_t plen = tal_count(p); + + if (fromwire_u16(&cursor, &plen) != WIRE_HSMD_SIGN_OPTION_WILL_FUND_OFFER) + return false; + fromwire_pubkey(&cursor, &plen, funding_pubkey); + *blockheight = fromwire_u32(&cursor, &plen); + *channel_fee_base_max_msat = fromwire_u32(&cursor, &plen); + *channel_fee_proportional_basis_max = fromwire_u16(&cursor, &plen); + return cursor != NULL; +} + +/* WIRE: HSMD_SIGN_OPTION_WILL_FUND_OFFER_REPLY */ +u8 *towire_hsmd_sign_option_will_fund_offer_reply(const tal_t *ctx, const secp256k1_ecdsa_signature *rsig) +{ + u8 *p = tal_arr(ctx, u8, 0); + + towire_u16(&p, WIRE_HSMD_SIGN_OPTION_WILL_FUND_OFFER_REPLY); + towire_secp256k1_ecdsa_signature(&p, rsig); + + return memcheck(p, tal_count(p)); +} +bool fromwire_hsmd_sign_option_will_fund_offer_reply(const void *p, secp256k1_ecdsa_signature *rsig) +{ + const u8 *cursor = p; + size_t plen = tal_count(p); + + if (fromwire_u16(&cursor, &plen) != WIRE_HSMD_SIGN_OPTION_WILL_FUND_OFFER_REPLY) + return false; + fromwire_secp256k1_ecdsa_signature(&cursor, &plen, rsig); + return cursor != NULL; +} +// SHA256STAMP:3096344d3102d59f92c00038c3ee948221f80969db85c305f7c15772a7f46593 diff --git a/hsmd/hsmd_wiregen.h b/hsmd/hsmd_wiregen.h index 1da52edbcb21..1623d611e49a 100644 --- a/hsmd/hsmd_wiregen.h +++ b/hsmd/hsmd_wiregen.h @@ -79,6 +79,9 @@ enum hsmd_wire { /* Sign a bolt12-style merkle hash */ WIRE_HSMD_SIGN_BOLT12 = 25, WIRE_HSMD_SIGN_BOLT12_REPLY = 125, + /* Sign an option_will_fund offer hash */ + WIRE_HSMD_SIGN_OPTION_WILL_FUND_OFFER = 26, + WIRE_HSMD_SIGN_OPTION_WILL_FUND_OFFER_REPLY = 126, }; const char *hsmd_wire_name(int e); @@ -281,6 +284,15 @@ bool fromwire_hsmd_sign_bolt12(const tal_t *ctx, const void *p, wirestring **mes u8 *towire_hsmd_sign_bolt12_reply(const tal_t *ctx, const struct bip340sig *sig); bool fromwire_hsmd_sign_bolt12_reply(const void *p, struct bip340sig *sig); +/* WIRE: HSMD_SIGN_OPTION_WILL_FUND_OFFER */ +/* Sign an option_will_fund offer hash */ +u8 *towire_hsmd_sign_option_will_fund_offer(const tal_t *ctx, const struct pubkey *funding_pubkey, u32 blockheight, u32 channel_fee_base_max_msat, u16 channel_fee_proportional_basis_max); +bool fromwire_hsmd_sign_option_will_fund_offer(const void *p, struct pubkey *funding_pubkey, u32 *blockheight, u32 *channel_fee_base_max_msat, u16 *channel_fee_proportional_basis_max); + +/* WIRE: HSMD_SIGN_OPTION_WILL_FUND_OFFER_REPLY */ +u8 *towire_hsmd_sign_option_will_fund_offer_reply(const tal_t *ctx, const secp256k1_ecdsa_signature *rsig); +bool fromwire_hsmd_sign_option_will_fund_offer_reply(const void *p, secp256k1_ecdsa_signature *rsig); + #endif /* LIGHTNING_HSMD_HSMD_WIREGEN_H */ -// SHA256STAMP:535c69a065c06a2e2ea151154ae83b53283d1c5b34e18b43a2c12c9444472548 +// SHA256STAMP:3096344d3102d59f92c00038c3ee948221f80969db85c305f7c15772a7f46593 diff --git a/hsmd/libhsmd.c b/hsmd/libhsmd.c index cef38c5b3527..0f2cacdcfb04 100644 --- a/hsmd/libhsmd.c +++ b/hsmd/libhsmd.c @@ -93,6 +93,9 @@ bool hsmd_check_client_capabilities(struct hsmd_client *client, case WIRE_HSMD_SIGN_MUTUAL_CLOSE_TX: return (client->capabilities & HSM_CAP_SIGN_CLOSING_TX) != 0; + case WIRE_HSMD_SIGN_OPTION_WILL_FUND_OFFER: + return (client->capabilities & HSM_CAP_SIGN_WILL_FUND_OFFER) != 0; + case WIRE_HSMD_INIT: case WIRE_HSMD_CLIENT_HSMFD: case WIRE_HSMD_SIGN_WITHDRAWAL: @@ -119,6 +122,7 @@ bool hsmd_check_client_capabilities(struct hsmd_client *client, case WIRE_HSMSTATUS_CLIENT_BAD_REQUEST: case WIRE_HSMD_SIGN_COMMITMENT_TX_REPLY: case WIRE_HSMD_SIGN_TX_REPLY: + case WIRE_HSMD_SIGN_OPTION_WILL_FUND_OFFER_REPLY: case WIRE_HSMD_GET_PER_COMMITMENT_POINT_REPLY: case WIRE_HSMD_CHECK_FUTURE_SECRET_REPLY: case WIRE_HSMD_GET_CHANNEL_BASEPOINTS_REPLY: @@ -468,6 +472,53 @@ static u8 *handle_sign_message(struct hsmd_client *c, const u8 *msg_in) return towire_hsmd_sign_message_reply(NULL, &rsig); } +/*~ lightningd asks us to sign a liquidity ad offer */ +static u8 *handle_sign_option_will_fund_offer(struct hsmd_client *c, + const u8 *msg_in) +{ + struct pubkey funding_pubkey; + u32 blockheight, channel_fee_base_max_msat; + u16 channel_fee_proportional_basis_max; + struct sha256_ctx sctx = SHA256_INIT; + struct sha256 sha; + secp256k1_ecdsa_signature sig; + struct privkey node_pkey; + + if (!fromwire_hsmd_sign_option_will_fund_offer(msg_in, + &funding_pubkey, + &blockheight, + &channel_fee_base_max_msat, + &channel_fee_proportional_basis_max)) + return hsmd_status_malformed_request(c, msg_in); + + /* BOLT- #2: + * - MUST set `signature` to the ECDSA signature of + * SHA256("option_will_fund" || `funding_pubkey`|| `blockheight` || + * `channel_fee_base_max_msat` || + * `channel_fee_proportional_basis_max`) + */ + sha256_update(&sctx, "option_will_fund", + strlen("option_will_fund")); + sha256_update(&sctx, &funding_pubkey, sizeof(funding_pubkey)); + sha256_update(&sctx, &blockheight, sizeof(blockheight)); + sha256_update(&sctx, &channel_fee_base_max_msat, + sizeof(channel_fee_base_max_msat)); + sha256_update(&sctx, &channel_fee_base_max_msat, + sizeof(channel_fee_base_max_msat)); + sha256_done(&sctx, &sha); + + node_key(&node_pkey, NULL); + + if (!secp256k1_ecdsa_sign(secp256k1_ctx, &sig, + sha.u.u8, + node_pkey.secret.data, + NULL, NULL)) + return hsmd_status_bad_request(c, msg_in, + "Failed to sign message"); + + return towire_hsmd_sign_option_will_fund_offer_reply(NULL, &sig); +} + /*~ lightningd asks us to sign a bolt12 (e.g. offer). */ static u8 *handle_sign_bolt12(struct hsmd_client *c, const u8 *msg_in) { @@ -1352,6 +1403,8 @@ u8 *hsmd_handle_client_message(const tal_t *ctx, struct hsmd_client *client, return handle_ecdh(client, msg); case WIRE_HSMD_SIGN_INVOICE: return handle_sign_invoice(client, msg); + case WIRE_HSMD_SIGN_OPTION_WILL_FUND_OFFER: + return handle_sign_option_will_fund_offer(client, msg); case WIRE_HSMD_SIGN_BOLT12: return handle_sign_bolt12(client, msg); case WIRE_HSMD_SIGN_MESSAGE: @@ -1397,6 +1450,7 @@ u8 *hsmd_handle_client_message(const tal_t *ctx, struct hsmd_client *client, case WIRE_HSMSTATUS_CLIENT_BAD_REQUEST: case WIRE_HSMD_SIGN_COMMITMENT_TX_REPLY: case WIRE_HSMD_SIGN_TX_REPLY: + case WIRE_HSMD_SIGN_OPTION_WILL_FUND_OFFER_REPLY: case WIRE_HSMD_GET_PER_COMMITMENT_POINT_REPLY: case WIRE_HSMD_CHECK_FUTURE_SECRET_REPLY: case WIRE_HSMD_GET_CHANNEL_BASEPOINTS_REPLY: From c4590ab2cf6e601dd9b44b026cda0abfcc043520 Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 8 Jun 2021 16:42:45 -0500 Subject: [PATCH 16/56] liquidity-ads: pipe through request to funder, update policy When a request comes through, we forward it over to the funder who uses the currently set policy to figure out how to handle it. Includes small update to the policy engine which decides whether or not to fund a request. Changelog-Added: Plugins: `openchannel2` hook now includes optional fields for a channel lease request --- common/lease_rates.c | 15 ++++++ common/lease_rates.h | 6 +++ doc/PLUGINS.md | 9 +++- lightningd/Makefile | 1 + lightningd/dual_open_control.c | 48 +++++++++++++++++++ plugins/funder.c | 58 +++++++++++++++++++++++ plugins/funder_policy.c | 23 ++++++++- plugins/funder_policy.h | 3 +- plugins/test/run-funder_policy.c | 80 ++++++++++++++++++++++++++++++++ 9 files changed, 239 insertions(+), 4 deletions(-) diff --git a/common/lease_rates.c b/common/lease_rates.c index cf0b402448f5..cd70734a0428 100644 --- a/common/lease_rates.c +++ b/common/lease_rates.c @@ -1,5 +1,6 @@ #include "config.h" #include +#include #include #include @@ -15,3 +16,17 @@ bool lease_rates_empty(struct lease_rates *rates) && rates->lease_fee_base_sat == 0 && rates->lease_fee_basis == 0; } + +bool lease_rates_set_chan_fee_base_msat(struct lease_rates *rates, + struct amount_msat amt) +{ + rates->channel_fee_max_base_msat = amt.millisatoshis; /* Raw: conversion */ + return rates->channel_fee_max_base_msat == amt.millisatoshis; /* Raw: comparsion */ +} + +bool lease_rates_set_lease_fee_sat(struct lease_rates *rates, + struct amount_sat amt) +{ + rates->lease_fee_base_sat = amt.satoshis; /* Raw: conversion */ + return rates->lease_fee_base_sat == amt.satoshis; /* Raw: comparsion */ +} diff --git a/common/lease_rates.h b/common/lease_rates.h index dd10e79fb57a..2c4a820025e2 100644 --- a/common/lease_rates.h +++ b/common/lease_rates.h @@ -3,7 +3,13 @@ #include "config.h" #include +struct amount_msat; +struct amount_sat; struct lease_rates; bool lease_rates_empty(struct lease_rates *rates); + +WARN_UNUSED_RESULT bool lease_rates_set_chan_fee_base_msat(struct lease_rates *rates, struct amount_msat amt); + +WARN_UNUSED_RESULT bool lease_rates_set_lease_fee_sat(struct lease_rates *rates, struct amount_sat amt); #endif /* LIGHTNING_COMMON_LEASE_RATES_H */ diff --git a/doc/PLUGINS.md b/doc/PLUGINS.md index fc0102452fdc..c28a2c110ac6 100644 --- a/doc/PLUGINS.md +++ b/doc/PLUGINS.md @@ -1100,7 +1100,10 @@ the v2 protocol, and it has passed basic sanity checks: "max_accepted_htlcs": 483, "channel_flags": 1 "locktime": 2453, - "channel_max_msat": "16777215000msat" + "channel_max_msat": "16777215000msat", + "requested_lease_msat": "100000000msat", + "lease_blockheight_start": 683990, + "node_blockheight": 683990 } } ``` @@ -1108,6 +1111,10 @@ the v2 protocol, and it has passed basic sanity checks: There may be additional fields, such as `shutdown_scriptpubkey`. You can see the definitions of these fields in [BOLT 2's description of the open_channel message][bolt2-open-channel]. +`requested_lease_msat`, `lease_blockheight_start`, and `node_blockheight` are +only present if the opening peer has requested a funding lease, +per `option_will_fund`. + The returned result must contain a `result` member which is either the string `reject` or `continue`. If `reject` and there's a member `error_message`, that member is sent to the peer diff --git a/lightningd/Makefile b/lightningd/Makefile index 1a4a1c4dbf0c..117ccf2250e1 100644 --- a/lightningd/Makefile +++ b/lightningd/Makefile @@ -100,6 +100,7 @@ LIGHTNINGD_COMMON_OBJS := \ common/json_helpers.o \ common/json_stream.o \ common/json_tok.o \ + common/lease_rates.o \ common/memleak.o \ common/msg_queue.o \ common/node_id.o \ diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index 1fa554eb996b..1fc83208a0ee 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -244,10 +245,15 @@ struct openchannel2_payload { /* What's the maximum amount of funding * this channel can hold */ struct amount_sat channel_max; + /* If they've requested funds, this is their request */ + struct amount_sat requested_lease_amt; + u32 lease_blockheight_start; + u32 node_blockheight; struct amount_sat accepter_funding; struct wally_psbt *psbt; const u8 *our_shutdown_scriptpubkey; + struct lease_rates *rates; char *err_msg; }; @@ -283,6 +289,14 @@ static void openchannel2_hook_serialize(struct openchannel2_payload *payload, payload->shutdown_scriptpubkey); json_add_amount_sat_only(stream, "channel_max_msat", payload->channel_max); + if (!amount_sat_zero(payload->requested_lease_amt)) { + json_add_amount_sat_only(stream, "requested_lease_msat", + payload->requested_lease_amt); + json_add_num(stream, "lease_blockheight_start", + payload->lease_blockheight_start); + json_add_num(stream, "node_blockheight", + payload->node_blockheight); + } json_object_end(stream); } @@ -699,6 +713,7 @@ openchannel2_hook_deserialize(struct openchannel2_payload *payload, const jsmntok_t *toks) { const u8 *shutdown_script; + const char *err; struct subd *dualopend = payload->dualopend; /* If our daemon died, we're done */ @@ -756,6 +771,38 @@ openchannel2_hook_deserialize(struct openchannel2_payload *payload, else payload->our_shutdown_scriptpubkey = shutdown_script; + + struct amount_sat sats; + struct amount_msat msats; + payload->rates = tal(payload, struct lease_rates); + err = json_scan(payload, buffer, toks, + "{lease_fee_base_msat:%" + ",lease_fee_basis:%" + ",channel_fee_max_base_msat:%" + ",channel_fee_max_proportional_thousandths:%" + ",funding_weight:%}", + JSON_SCAN(json_to_sat, &sats), + JSON_SCAN(json_to_u16, + &payload->rates->lease_fee_basis), + JSON_SCAN(json_to_msat, &msats), + JSON_SCAN(json_to_u16, + &payload->rates->channel_fee_max_proportional_thousandths), + JSON_SCAN(json_to_u16, + &payload->rates->funding_weight)); + + /* It's possible they didn't send these back! */ + if (err) + payload->rates = tal_free(payload->rates); + + /* Convert to u32s */ + if (payload->rates && + !lease_rates_set_lease_fee_sat(payload->rates, sats)) + fatal("Plugin sent overflowing `lease_fee_base_msat`"); + + if (payload->rates && + !lease_rates_set_chan_fee_base_msat(payload->rates, msats)) + fatal("Plugin sent overflowing `channel_fee_max_base_msat`"); + /* Add a serial_id to everything that doesn't have one yet */ if (payload->psbt) psbt_add_serials(payload->psbt, TX_ACCEPTER); @@ -1699,6 +1746,7 @@ static void accepter_got_offer(struct subd *dualopend, * the plugin */ payload->feerate_our_min = feerate_min(dualopend->ld, NULL); payload->feerate_our_max = feerate_max(dualopend->ld, NULL); + payload->node_blockheight = get_block_height(dualopend->ld->topology); payload->channel_max = chainparams->max_funding; if (feature_negotiated(dualopend->ld->our_features, diff --git a/plugins/funder.c b/plugins/funder.c index 891154dc63d4..e2e5997cc774 100644 --- a/plugins/funder.c +++ b/plugins/funder.c @@ -282,6 +282,9 @@ struct open_info { struct amount_sat channel_max; u64 funding_feerate_perkw; u32 locktime; + u32 lease_blockheight; + u32 node_blockheight; + struct amount_sat requested_lease; }; static struct command_result * @@ -322,6 +325,11 @@ psbt_funded(struct command *cmd, json_add_amount_msat_only(response, "our_funding_msat", our_funding_msat); + /* If we're accepting an lease request, *and* they've + * requested one, fill in our most recent infos */ + if (current_policy->rates && !amount_sat_zero(info->requested_lease)) + json_add_lease_rates(response, current_policy->rates); + return command_finished(cmd, response); } @@ -419,6 +427,7 @@ listfunds_success(struct command *cmd, info->their_funding, available_funds, info->channel_max, + info->requested_lease, &info->our_funding); plugin_log(cmd->plugin, LOG_DBG, "Policy %s returned funding amount of %s. %s", @@ -531,6 +540,21 @@ json_openchannel2_call(struct command *cmd, err, json_tok_full_len(params), json_tok_full(buf, params)); + err = json_scan(tmpctx, buf, params, + "{openchannel2:{" + "requested_lease_msat:%" + ",lease_blockheight_start:%" + ",node_blockheight:%}}", + JSON_SCAN(json_to_sat, &info->requested_lease), + JSON_SCAN(json_to_u32, &info->node_blockheight), + JSON_SCAN(json_to_u32, &info->lease_blockheight)); + + /* These aren't necessarily included */ + if (err) { + info->requested_lease = AMOUNT_SAT(0); + info->node_blockheight = 0; + info->lease_blockheight = 0; + } /* If there's no channel_max, it's actually infinity */ err = json_scan(tmpctx, buf, params, @@ -553,6 +577,40 @@ json_openchannel2_call(struct command *cmd, return command_hook_success(cmd); } + /* Check that their block height isn't too far behind */ + if (!amount_sat_zero(info->requested_lease)) { + u32 upper_bound, lower_bound; + + /* BOLT- #2: + * The receiving node: + * - MAY fail the negotiation if: ... + * - if the `option_will_fund` tlv is present and: + * - the `blockheight` is considered too far in the + * past or future + */ + /* We consider 24 hrs too far out */ + upper_bound = info->node_blockheight + 24 * 6; + lower_bound = info->node_blockheight - 24 * 6; + + /* Check overflow */ + if (upper_bound < info->node_blockheight) + upper_bound = -1; + if (lower_bound > info->node_blockheight) + lower_bound = 0; + + if (upper_bound < info->lease_blockheight + || lower_bound > info->lease_blockheight) { + + plugin_log(cmd->plugin, LOG_DBG, + "their blockheight %d is out of" + " our bounds (ours is %d)", + info->lease_blockheight, + info->node_blockheight); + + return command_hook_success(cmd); + } + } + /* Figure out what our funds are */ req = jsonrpc_request_start(cmd->plugin, cmd, "listfunds", diff --git a/plugins/funder_policy.c b/plugins/funder_policy.c index 428b4c42f809..1aefdfef5221 100644 --- a/plugins/funder_policy.c +++ b/plugins/funder_policy.c @@ -174,12 +174,17 @@ apply_fuzz(u32 fuzz_factor, struct amount_sat val) static struct amount_sat apply_policy(struct funder_policy *policy, struct amount_sat their_funding, + struct amount_sat requested_lease, struct amount_sat available_funds) { struct amount_sat our_funding; switch (policy->opt) { case MATCH: + /* For matches, we use requested funding, if availalbe */ + if (!amount_sat_zero(requested_lease)) + their_funding = requested_lease; + /* if this fails, it implies ludicrous funding offer, *and* * > 100% match. Just Say No, kids. */ if (!amount_sat_scale(&our_funding, their_funding, @@ -207,12 +212,23 @@ calculate_our_funding(struct funder_policy *policy, struct amount_sat their_funding, struct amount_sat available_funds, struct amount_sat channel_max, + struct amount_sat requested_lease, struct amount_sat *our_funding) { struct amount_sat avail_channel_space, net_available_funds; + /* Are we only funding lease requests ? */ + if (policy->leases_only && amount_sat_zero(requested_lease)) { + *our_funding = AMOUNT_SAT(0); + return tal_fmt(tmpctx, + "Skipping funding open; leases-only=true" + " and this open isn't asking for a lease"); + } + /* Are we skipping this one? */ - if (pseudorand(100) >= policy->fund_probability) { + if (pseudorand(100) >= policy->fund_probability + /* We don't skip lease requests */ + && amount_sat_zero(requested_lease)) { *our_funding = AMOUNT_SAT(0); return tal_fmt(tmpctx, "Skipping, failed fund_probability test"); @@ -269,7 +285,10 @@ calculate_our_funding(struct funder_policy *policy, } /* What's our amount, given our policy */ - *our_funding = apply_policy(policy, their_funding, available_funds); + *our_funding = apply_policy(policy, + their_funding, + requested_lease, + available_funds); /* Don't return an 'error' if we're already at 0 */ if (amount_sat_zero(*our_funding)) diff --git a/plugins/funder_policy.h b/plugins/funder_policy.h index dfb12e19977a..f554bdbe5104 100644 --- a/plugins/funder_policy.h +++ b/plugins/funder_policy.h @@ -9,7 +9,7 @@ struct node_id; /* Policy Options */ enum funder_opt { - /* Use their_funding as the starting + /* Use their_funding/requested_amt as the starting * point for your contribution */ MATCH, @@ -96,6 +96,7 @@ calculate_our_funding(struct funder_policy *policy, struct amount_sat their_funding, struct amount_sat available_funds, struct amount_sat channel_max, + struct amount_sat lease_request, struct amount_sat *our_funding); /* Get the name of this policy option */ diff --git a/plugins/test/run-funder_policy.c b/plugins/test/run-funder_policy.c index a61ca864a033..09ca6a3a9ee8 100644 --- a/plugins/test/run-funder_policy.c +++ b/plugins/test/run-funder_policy.c @@ -33,6 +33,7 @@ struct test_case { struct amount_sat their_funds; struct amount_sat available_funds; struct amount_sat channel_max; + struct amount_sat lease_request; struct funder_policy policy; @@ -46,6 +47,7 @@ struct test_case cases[] = { .their_funds = AMOUNT_SAT(5000), .available_funds = AMOUNT_SAT(100000), .channel_max = AMOUNT_SAT(11000), + .lease_request = AMOUNT_SAT(0), .policy = { .opt = FIXED, .mod = 1111, @@ -56,6 +58,7 @@ struct test_case cases[] = { .fuzz_factor = 0, .reserve_tank = AMOUNT_SAT(0), .fund_probability = 100, + .leases_only = false, }, .exp_our_funds = AMOUNT_SAT(1111), @@ -66,6 +69,7 @@ struct test_case cases[] = { .their_funds = AMOUNT_SAT(5000), .available_funds = AMOUNT_SAT(500), .channel_max = AMOUNT_SAT(11000), + .lease_request = AMOUNT_SAT(0), .policy = { .opt = MATCH, .mod = 0, @@ -76,6 +80,7 @@ struct test_case cases[] = { .fuzz_factor = 0, .reserve_tank = AMOUNT_SAT(0), .fund_probability = 100, + .leases_only = false, }, .exp_our_funds = AMOUNT_SAT(0), @@ -86,6 +91,7 @@ struct test_case cases[] = { .their_funds = AMOUNT_SAT(5000), .available_funds = AMOUNT_SAT(6000), .channel_max = AMOUNT_SAT(11000), + .lease_request = AMOUNT_SAT(0), .policy = { .opt = MATCH, .mod = 100, @@ -96,6 +102,7 @@ struct test_case cases[] = { .fuzz_factor = 0, .reserve_tank = AMOUNT_SAT(0), .fund_probability = 100, + .leases_only = false, }, .exp_our_funds = AMOUNT_SAT(5000), @@ -106,6 +113,7 @@ struct test_case cases[] = { .their_funds = AMOUNT_SAT(2500), .available_funds = AMOUNT_SAT(6000), .channel_max = AMOUNT_SAT(11000), + .lease_request = AMOUNT_SAT(0), .policy = { .opt = MATCH, .mod = 200, @@ -116,6 +124,7 @@ struct test_case cases[] = { .fuzz_factor = 0, .reserve_tank = AMOUNT_SAT(0), .fund_probability = 100, + .leases_only = false, }, .exp_our_funds = AMOUNT_SAT(5000), @@ -126,6 +135,7 @@ struct test_case cases[] = { .their_funds = AMOUNT_SAT(2500), .available_funds = AMOUNT_SAT(5000), .channel_max = AMOUNT_SAT(11000), + .lease_request = AMOUNT_SAT(0), .policy = { .opt = AVAILABLE, .mod = 0, @@ -136,6 +146,7 @@ struct test_case cases[] = { .fuzz_factor = 0, .reserve_tank = AMOUNT_SAT(0), .fund_probability = 100, + .leases_only = false, }, .exp_our_funds = AMOUNT_SAT(0), @@ -146,6 +157,7 @@ struct test_case cases[] = { .their_funds = AMOUNT_SAT(2500), .available_funds = AMOUNT_SAT(3000), .channel_max = AMOUNT_SAT(11000), + .lease_request = AMOUNT_SAT(0), .policy = { .opt = AVAILABLE, .mod = 50, @@ -156,6 +168,7 @@ struct test_case cases[] = { .fuzz_factor = 0, .reserve_tank = AMOUNT_SAT(0), .fund_probability = 100, + .leases_only = false, }, .exp_our_funds = AMOUNT_SAT(1500), @@ -166,6 +179,7 @@ struct test_case cases[] = { .their_funds = AMOUNT_SAT(2500), .available_funds = AMOUNT_SAT(5000), .channel_max = AMOUNT_SAT(11000), + .lease_request = AMOUNT_SAT(0), .policy = { .opt = AVAILABLE, .mod = 100, @@ -176,6 +190,7 @@ struct test_case cases[] = { .fuzz_factor = 0, .reserve_tank = AMOUNT_SAT(0), .fund_probability = 100, + .leases_only = false, }, .exp_our_funds = AMOUNT_SAT(5000), @@ -198,6 +213,7 @@ struct test_case cases[] = { .fuzz_factor = 0, .reserve_tank = AMOUNT_SAT(0), .fund_probability = 100, + .leases_only = false, }, .exp_our_funds = AMOUNT_SAT(900), @@ -208,6 +224,7 @@ struct test_case cases[] = { .their_funds = AMOUNT_SAT(5000), .available_funds = AMOUNT_SAT(5000), .channel_max = AMOUNT_SAT(5500), + .lease_request = AMOUNT_SAT(0), .policy = { .opt = FIXED, .mod = 1002, @@ -218,6 +235,7 @@ struct test_case cases[] = { .fuzz_factor = 0, .reserve_tank = AMOUNT_SAT(0), .fund_probability = 100, + .leases_only = false, }, .exp_our_funds = AMOUNT_SAT(500), @@ -228,6 +246,7 @@ struct test_case cases[] = { .their_funds = AMOUNT_SAT(5000), .available_funds = AMOUNT_SAT(500), .channel_max = AMOUNT_SAT(10000), + .lease_request = AMOUNT_SAT(0), .policy = { .opt = FIXED, .mod = 1001, @@ -238,6 +257,7 @@ struct test_case cases[] = { .fuzz_factor = 0, .reserve_tank = AMOUNT_SAT(0), .fund_probability = 100, + .leases_only = false, }, .exp_our_funds = AMOUNT_SAT(500), @@ -248,6 +268,7 @@ struct test_case cases[] = { .their_funds = AMOUNT_SAT(5000), .available_funds = AMOUNT_SAT(1000), .channel_max = AMOUNT_SAT(10000), + .lease_request = AMOUNT_SAT(0), .policy = { .opt = FIXED, .mod = 999, @@ -258,6 +279,7 @@ struct test_case cases[] = { .fuzz_factor = 0, .reserve_tank = AMOUNT_SAT(0), .fund_probability = 100, + .leases_only = false, }, .exp_our_funds = AMOUNT_SAT(0), @@ -268,6 +290,7 @@ struct test_case cases[] = { .their_funds = AMOUNT_SAT(5001), .available_funds = AMOUNT_SAT(5000), .channel_max = AMOUNT_SAT(10000), + .lease_request = AMOUNT_SAT(0), .policy = { .opt = FIXED, .mod = 998, @@ -278,6 +301,7 @@ struct test_case cases[] = { .fuzz_factor = 0, .reserve_tank = AMOUNT_SAT(0), .fund_probability = 100, + .leases_only = false, }, .exp_our_funds = AMOUNT_SAT(0), @@ -288,6 +312,7 @@ struct test_case cases[] = { .their_funds = AMOUNT_SAT(5000), .available_funds = AMOUNT_SAT(1000), .channel_max = AMOUNT_SAT(10000), + .lease_request = AMOUNT_SAT(0), .policy = { .opt = FIXED, .mod = 997, @@ -298,6 +323,7 @@ struct test_case cases[] = { .fuzz_factor = 0, .reserve_tank = AMOUNT_SAT(100), .fund_probability = 100, + .leases_only = false, }, .exp_our_funds = AMOUNT_SAT(900), @@ -308,6 +334,7 @@ struct test_case cases[] = { .their_funds = AMOUNT_SAT(5000), .available_funds = AMOUNT_SAT(999), .channel_max = AMOUNT_SAT(10000), + .lease_request = AMOUNT_SAT(0), .policy = { .opt = FIXED, .mod = 996, @@ -318,6 +345,7 @@ struct test_case cases[] = { .fuzz_factor = 0, .reserve_tank = AMOUNT_SAT(1000), .fund_probability = 100, + .leases_only = false, }, .exp_our_funds = AMOUNT_SAT(0), @@ -328,6 +356,7 @@ struct test_case cases[] = { .their_funds = AMOUNT_SAT(5000), .available_funds = AMOUNT_SAT(5000), .channel_max = AMOUNT_SAT(5000), + .lease_request = AMOUNT_SAT(0), .policy = { .opt = FIXED, .mod = 995, @@ -338,6 +367,7 @@ struct test_case cases[] = { .fuzz_factor = 0, .reserve_tank = AMOUNT_SAT(1000), .fund_probability = 100, + .leases_only = false, }, .exp_our_funds = AMOUNT_SAT(0), @@ -348,6 +378,7 @@ struct test_case cases[] = { .their_funds = AMOUNT_SAT(5000), .available_funds = AMOUNT_SAT(5000), .channel_max = AMOUNT_SAT(11000), + .lease_request = AMOUNT_SAT(0), .policy = { .opt = FIXED, .mod = 988, @@ -358,6 +389,51 @@ struct test_case cases[] = { .fuzz_factor = 0, .reserve_tank = AMOUNT_SAT(0), .fund_probability = 100, + .leases_only = false, + }, + + .exp_our_funds = AMOUNT_SAT(0), + .expect_err = true, + }, + /* By default, use lease request as ceiling */ + { + .their_funds = AMOUNT_SAT(5000), + .available_funds = AMOUNT_SAT(100000), + .channel_max = AMOUNT_SAT(11000), + .lease_request = AMOUNT_SAT(980), + .policy = { + .opt = MATCH, + .mod = 100, + .min_their_funding = AMOUNT_SAT(0), + .max_their_funding = AMOUNT_SAT(10000), + .per_channel_max = AMOUNT_SAT(100000), + .per_channel_min = AMOUNT_SAT(0), + .fuzz_factor = 0, + .reserve_tank = AMOUNT_SAT(0), + .fund_probability = 100, + .leases_only = false, + }, + + .exp_our_funds = AMOUNT_SAT(980), + .expect_err = false, + }, + /* Only fund lease requests */ + { + .their_funds = AMOUNT_SAT(5000), + .available_funds = AMOUNT_SAT(100000), + .channel_max = AMOUNT_SAT(11000), + .lease_request = AMOUNT_SAT(0), + .policy = { + .opt = FIXED, + .mod = 985, + .min_their_funding = AMOUNT_SAT(0), + .max_their_funding = AMOUNT_SAT(10000), + .per_channel_max = AMOUNT_SAT(100000), + .per_channel_min = AMOUNT_SAT(0), + .fuzz_factor = 0, + .reserve_tank = AMOUNT_SAT(0), + .fund_probability = 100, + .leases_only = true, }, .exp_our_funds = AMOUNT_SAT(0), @@ -380,6 +456,7 @@ static void check_fuzzing(struct test_case fuzzcase) fuzzcase.their_funds, fuzzcase.available_funds, fuzzcase.channel_max, + fuzzcase.lease_request, &our_funds); if (amount_sat_greater(our_funds, fuzz_max)) fuzz_max = our_funds; @@ -412,6 +489,7 @@ int main(int argc, const char *argv[]) AMOUNT_SAT(50000), AMOUNT_SAT(50000), AMOUNT_SAT(100000), + AMOUNT_SAT(0), &our_funds); assert(amount_sat_eq(empty, our_funds)); assert(!err); @@ -421,6 +499,7 @@ int main(int argc, const char *argv[]) cases[i].their_funds, cases[i].available_funds, cases[i].channel_max, + cases[i].lease_request, &our_funds); if (!amount_sat_eq(cases[i].exp_our_funds, our_funds)) { fprintf(stderr, "FAIL policy: %s. expected %s, got %s\n", @@ -454,6 +533,7 @@ int main(int argc, const char *argv[]) flipcase.their_funds, flipcase.available_funds, flipcase.channel_max, + flipcase.lease_request, &our_funds); if (!amount_sat_eq(our_funds, AMOUNT_SAT(0))) flipcount++; From ff0005738fa5196294b22f92bde4180240ca4831 Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 8 Jun 2021 16:50:41 -0500 Subject: [PATCH 17/56] liquidity-ad: request amount, pass through to dualopend Changelog-Added: EXPERIMENTAL-DUAL-FUND: JSON-RPC: openchannel_init now takes a `requested_amt`, which is an amount to request from peer --- contrib/pyln-client/pyln/client/lightning.py | 3 +- doc/lightning-openchannel_init.7 | 18 ++++++- doc/lightning-openchannel_init.7.md | 14 ++++- lightningd/dual_open_control.c | 14 +++-- openingd/dualopend.c | 54 ++++++++++++++++++-- openingd/dualopend_wire.csv | 6 +++ openingd/dualopend_wiregen.c | 34 +++++++++--- openingd/dualopend_wiregen.h | 15 +++--- 8 files changed, 131 insertions(+), 27 deletions(-) diff --git a/contrib/pyln-client/pyln/client/lightning.py b/contrib/pyln-client/pyln/client/lightning.py index f4e53f31935d..3df040ad1cca 100644 --- a/contrib/pyln-client/pyln/client/lightning.py +++ b/contrib/pyln-client/pyln/client/lightning.py @@ -1006,7 +1006,7 @@ def pay(self, bolt11, msatoshi=None, label=None, riskfactor=None, } return self.call("pay", payload) - def openchannel_init(self, node_id, channel_amount, psbt, feerate=None, funding_feerate=None, announce=True, close_to=None, *args, **kwargs): + def openchannel_init(self, node_id, channel_amount, psbt, feerate=None, funding_feerate=None, announce=True, close_to=None, request_amt=None, *args, **kwargs): """Initiate an openchannel with a peer """ payload = { "id": node_id, @@ -1016,6 +1016,7 @@ def openchannel_init(self, node_id, channel_amount, psbt, feerate=None, funding_ "funding_feerate": funding_feerate, "announce": announce, "close_to": close_to, + "request_amt": request_amt, } return self.call("openchannel_init", payload) diff --git a/doc/lightning-openchannel_init.7 b/doc/lightning-openchannel_init.7 index a92edbb7b4e0..d3cde84c77a7 100644 --- a/doc/lightning-openchannel_init.7 +++ b/doc/lightning-openchannel_init.7 @@ -3,7 +3,7 @@ lightning-openchannel_init - Command to initiate a channel to a peer .SH SYNOPSIS -\fBopenchannel_init\fR \fIid\fR \fIamount\fR \fIinitalpsbt\fR [\fIcommitment_feerate\fR] [\fIfunding_feerate\fR] [\fIannounce\fR] [\fIclose_to\fR] +\fBopenchannel_init\fR \fIid\fR \fIamount\fR \fIinitalpsbt\fR [\fIcommitment_feerate\fR] [\fIfunding_feerate\fR] [\fIannounce\fR] [\fIclose_to\fR] [\fIrequest_amt\fR] .SH DESCRIPTION @@ -43,6 +43,11 @@ funding transaction\. Defaults to 'opening' feerate\. sent on close\. Only valid if both peers have negotiated \fBoption_upfront_shutdown_script\fR\. + +\fIrequest_amt\fR is an amount of liquidity you'd like to lease from the peer\. +If peer supports \fBoption_will_fund\fR, indicates to them to include this +much liquidity into the channel\. + .SH RETURN VALUE On success, returns the \fIchannel_id\fR for this channel; an updated @@ -57,6 +62,15 @@ If the peer does not support \fBoption_dual_fund\fR, this command will return an error\. +If you sent a \fIrequest_amt\fR and the peer supports \fBoption_will_fund\fR and is +interested in leasing you liquidity in this channel, returns their updated +channel fee max (\fIchannel_fee_proportional_basis\fR, \fIchannel_fee_base_msat\fR), +updated rate card for the lease fee (\fIlease_fee_proportional_basis\fR, +\fIlease_fee_base_sat\fR) and their on-chain weight \fIweight_charge\fR, which will +be added to the lease fee at a rate of \fIfunding_feerate\fR \fI \fRweight_charge* +/ 1000\. + + On error the returned object will contain \fBcode\fR and \fBmessage\fR properties, with \fBcode\fR being one of the following: @@ -99,4 +113,4 @@ lightning-fundchannel_\fBcomplete\fR(7), \fBlightning-fundchannel\fR(7), Main web site: \fIhttps://github.com/ElementsProject/lightning\fR -\" SHA256STAMP:8e37cb8813751e06f59b108e8a335b5b5269e5764c346838a6ddf79138ccea6e +\" SHA256STAMP:4a2cfb31a80ccc03c7dda75e52e8c67fa99aeae0dd6f6640e155f5f4e161d218 diff --git a/doc/lightning-openchannel_init.7.md b/doc/lightning-openchannel_init.7.md index 0385e1acb530..d39bda276473 100644 --- a/doc/lightning-openchannel_init.7.md +++ b/doc/lightning-openchannel_init.7.md @@ -4,7 +4,7 @@ lightning-openchannel\_init -- Command to initiate a channel to a peer SYNOPSIS -------- -**openchannel_init** *id* *amount* *initalpsbt* \[*commitment_feerate*\] \[*funding_feerate*\] \[*announce*\] \[*close_to*\] +**openchannel_init** *id* *amount* *initalpsbt* \[*commitment_feerate*\] \[*funding_feerate*\] \[*announce*\] \[*close_to*\] \[*request_amt*\] DESCRIPTION ----------- @@ -38,6 +38,10 @@ funding transaction. Defaults to 'opening' feerate. sent on close. Only valid if both peers have negotiated `option_upfront_shutdown_script`. +*request_amt* is an amount of liquidity you'd like to lease from the peer. +If peer supports `option_will_fund`, indicates to them to include this +much liquidity into the channel. + RETURN VALUE ------------ @@ -52,6 +56,14 @@ in the *psbt*. If the peer does not support `option_dual_fund`, this command will return an error. +If you sent a *request_amt* and the peer supports `option_will_fund` and is +interested in leasing you liquidity in this channel, returns their updated +channel fee max (*channel_fee_proportional_basis*, *channel_fee_base_msat*), +updated rate card for the lease fee (*lease_fee_proportional_basis*, +*lease_fee_base_sat*) and their on-chain weight *weight_charge*, which will +be added to the lease fee at a rate of *funding_feerate* * *weight_charge* +/ 1000. + On error the returned object will contain `code` and `message` properties, with `code` being one of the following: diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index 1fc83208a0ee..f7779f282a72 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -701,7 +701,8 @@ openchannel2_hook_cb(struct openchannel2_payload *payload STEALS) msg = towire_dualopend_got_offer_reply(NULL, payload->accepter_funding, payload->psbt, - payload->our_shutdown_scriptpubkey); + payload->our_shutdown_scriptpubkey, + payload->rates); subd_send_msg(dualopend, take(msg)); } @@ -1733,7 +1734,9 @@ static void accepter_got_offer(struct subd *dualopend, &payload->max_accepted_htlcs, &payload->channel_flags, &payload->locktime, - &payload->shutdown_scriptpubkey)) { + &payload->shutdown_scriptpubkey, + &payload->requested_lease_amt, + &payload->lease_blockheight_start)) { channel_internal_error(channel, "Bad DUALOPEND_GOT_OFFER: %s", tal_hex(tmpctx, msg)); return; @@ -2324,7 +2327,7 @@ static struct command_result *json_openchannel_init(struct command *cmd, bool *announce_channel; u32 *feerate_per_kw_funding; u32 *feerate_per_kw; - struct amount_sat *amount, psbt_val; + struct amount_sat *amount, psbt_val, *request_amt; struct wally_psbt *psbt; const u8 *our_upfront_shutdown_script; struct open_attempt *oa; @@ -2338,6 +2341,7 @@ static struct command_result *json_openchannel_init(struct command *cmd, p_opt("funding_feerate", param_feerate, &feerate_per_kw_funding), p_opt_def("announce", param_bool, &announce_channel, true), p_opt("close_to", param_bitcoin_address, &our_upfront_shutdown_script), + p_opt_def("request_amt", param_sat, &request_amt, AMOUNT_SAT(0)), NULL)) return command_param_failed(); @@ -2469,7 +2473,9 @@ static struct command_result *json_openchannel_init(struct command *cmd, oa->our_upfront_shutdown_script, *feerate_per_kw, *feerate_per_kw_funding, - channel->channel_flags); + channel->channel_flags, + *request_amt, + get_block_height(cmd->ld->topology)); subd_send_msg(channel->owner, take(msg)); return command_still_pending(cmd); diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 06c2f9a7bb97..21a6bc50beaa 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -119,6 +119,9 @@ struct tx_state { /* Have we gotten the peer's tx-sigs yet? */ bool remote_funding_sigs_rcvd; + + /* Rates that we're using for this open... */ + struct lease_rates *rates; }; static struct tx_state *new_tx_state(const tal_t *ctx) @@ -1883,7 +1886,8 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) struct channel_id cid, full_cid; char *err_reason; u8 *msg; - struct amount_sat total; + struct amount_sat total, requested_amt; + u32 lease_blockheight_start; enum dualopend_wire msg_type; struct tx_state *tx_state = state->tx_state; @@ -1918,6 +1922,19 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) } else state->upfront_shutdown_script[REMOTE] = NULL; + /* This is an `option_will_fund` request */ + if (open_tlv->request_funds) { + /* FIXME: Do we support this? */ + requested_amt + = amount_sat(open_tlv->request_funds->requested_sats); + lease_blockheight_start + = open_tlv->request_funds->blockheight; + } else { + requested_amt = AMOUNT_SAT(0); + lease_blockheight_start = 0; + } + + /* BOLT-* #2 * If the peer's revocation basepoint is unknown (e.g. * `open_channel2`), a temporary `channel_id` should be found @@ -1984,7 +2001,9 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) tx_state->remoteconf.max_accepted_htlcs, state->channel_flags, tx_state->tx_locktime, - state->upfront_shutdown_script[REMOTE]); + state->upfront_shutdown_script[REMOTE], + requested_amt, + lease_blockheight_start); wire_sync_write(REQ_FD, take(msg)); msg = wire_sync_read(tmpctx, REQ_FD); @@ -1999,7 +2018,8 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) if (!fromwire_dualopend_got_offer_reply(state, msg, &tx_state->accepter_funding, &tx_state->psbt, - &state->upfront_shutdown_script[LOCAL])) + &state->upfront_shutdown_script[LOCAL], + &tx_state->rates)) master_badmsg(WIRE_DUALOPEND_GOT_OFFER_REPLY, msg); if (!tx_state->psbt) @@ -2009,6 +2029,19 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) /* Locktimes must match! */ tx_state->psbt->tx->locktime = tx_state->tx_locktime; + /* BOLT- #2: + * + * - if they decide to accept the offer: + * ... + * - MUST set `funding_satoshis` to a value greater than 0msat + */ + if (tx_state->rates && amount_sat_zero(tx_state->accepter_funding)) { + status_broken("opt_will_fund ad passed in, but no funding"); + negotiation_failed(state, "We're unable to accept" + " your lease offer."); + return; + } + /* Check that total funding doesn't overflow */ if (!amount_sat_add(&total, tx_state->opener_funding, tx_state->accepter_funding)) @@ -2378,7 +2411,8 @@ static void opener_start(struct state *state, u8 *msg) struct tlv_accept_tlvs *a_tlv; struct channel_id cid; char *err_reason; - struct amount_sat total; + struct amount_sat total, requested_sats; + u32 current_blockheight; struct tx_state *tx_state = state->tx_state; if (!fromwire_dualopend_opener_init(state, msg, @@ -2387,7 +2421,9 @@ static void opener_start(struct state *state, u8 *msg) &state->upfront_shutdown_script[LOCAL], &state->feerate_per_kw_commitment, &state->feerate_per_kw_funding, - &state->channel_flags)) + &state->channel_flags, + &requested_sats, + ¤t_blockheight)) master_badmsg(WIRE_DUALOPEND_OPENER_INIT, msg); state->our_role = TX_INITIATOR; @@ -2417,6 +2453,14 @@ static void opener_start(struct state *state, u8 *msg) state->upfront_shutdown_script[LOCAL]; } + if (!amount_sat_zero(requested_sats)) { + open_tlv->request_funds = + tal(open_tlv, struct tlv_opening_tlvs_request_funds); + open_tlv->request_funds->requested_sats = + requested_sats.satoshis; /* Raw: struct -> wire */ + open_tlv->request_funds->blockheight = current_blockheight; + } + msg = towire_open_channel2(NULL, &chainparams->genesis_blockhash, &state->channel_id, diff --git a/openingd/dualopend_wire.csv b/openingd/dualopend_wire.csv index 217f935aa1a2..9f1343f1ed0f 100644 --- a/openingd/dualopend_wire.csv +++ b/openingd/dualopend_wire.csv @@ -9,6 +9,7 @@ #include #include #include +#include msgtype,dualopend_init,7000 # Which network are we configured for? @@ -80,6 +81,8 @@ msgdata,dualopend_got_offer,channel_flags,u8, msgdata,dualopend_got_offer,locktime,u32, msgdata,dualopend_got_offer,shutdown_len,u16, msgdata,dualopend_got_offer,shutdown_scriptpubkey,u8,shutdown_len +msgdata,dualopend_got_offer,requested_amt,amount_sat, +msgdata,dualopend_got_offer,lease_blockheight_start,u32, # master->dualopend: reply back with our first funding info/contribs msgtype,dualopend_got_offer_reply,7105 @@ -87,6 +90,7 @@ msgdata,dualopend_got_offer_reply,accepter_funding,amount_sat, msgdata,dualopend_got_offer_reply,psbt,wally_psbt, msgdata,dualopend_got_offer_reply,shutdown_len,u16, msgdata,dualopend_got_offer_reply,our_shutdown_scriptpubkey,?u8,shutdown_len +msgdata,dualopend_got_offer_reply,lease_rates,?lease_rates, # dualopend->master: they offered a RBF, should we continue? msgtype,dualopend_got_rbf_offer,7500 @@ -161,6 +165,8 @@ msgdata,dualopend_opener_init,local_shutdown_scriptpubkey,u8,local_shutdown_len msgdata,dualopend_opener_init,feerate_per_kw,u32, msgdata,dualopend_opener_init,feerate_per_kw_funding,u32, msgdata,dualopend_opener_init,channel_flags,u8, +msgdata,dualopend_opener_init,requested_sats,amount_sat, +msgdata,dualopend_opener_init,blockheight,u32, # dualopend->master received tx_sigs from peer msgtype,dualopend_funding_sigs,7010 diff --git a/openingd/dualopend_wiregen.c b/openingd/dualopend_wiregen.c index 21d658ecb710..85d9025aa7e0 100644 --- a/openingd/dualopend_wiregen.c +++ b/openingd/dualopend_wiregen.c @@ -249,7 +249,7 @@ bool fromwire_dualopend_reinit(const tal_t *ctx, const void *p, const struct cha /* WIRE: DUALOPEND_GOT_OFFER */ /* dualopend->master: they offered channel */ -u8 *towire_dualopend_got_offer(const tal_t *ctx, const struct channel_id *channel_id, struct amount_sat opener_funding, struct amount_sat dust_limit_satoshis, struct amount_msat max_htlc_value_in_flight_msat, struct amount_msat htlc_minimum_msat, u32 feerate_per_kw_funding, u32 feerate_per_kw_commitment, u16 to_self_delay, u16 max_accepted_htlcs, u8 channel_flags, u32 locktime, const u8 *shutdown_scriptpubkey) +u8 *towire_dualopend_got_offer(const tal_t *ctx, const struct channel_id *channel_id, struct amount_sat opener_funding, struct amount_sat dust_limit_satoshis, struct amount_msat max_htlc_value_in_flight_msat, struct amount_msat htlc_minimum_msat, u32 feerate_per_kw_funding, u32 feerate_per_kw_commitment, u16 to_self_delay, u16 max_accepted_htlcs, u8 channel_flags, u32 locktime, const u8 *shutdown_scriptpubkey, struct amount_sat requested_amt, u32 lease_blockheight_start) { u16 shutdown_len = tal_count(shutdown_scriptpubkey); u8 *p = tal_arr(ctx, u8, 0); @@ -268,10 +268,12 @@ u8 *towire_dualopend_got_offer(const tal_t *ctx, const struct channel_id *channe towire_u32(&p, locktime); towire_u16(&p, shutdown_len); towire_u8_array(&p, shutdown_scriptpubkey, shutdown_len); + towire_amount_sat(&p, requested_amt); + towire_u32(&p, lease_blockheight_start); return memcheck(p, tal_count(p)); } -bool fromwire_dualopend_got_offer(const tal_t *ctx, const void *p, struct channel_id *channel_id, struct amount_sat *opener_funding, struct amount_sat *dust_limit_satoshis, struct amount_msat *max_htlc_value_in_flight_msat, struct amount_msat *htlc_minimum_msat, u32 *feerate_per_kw_funding, u32 *feerate_per_kw_commitment, u16 *to_self_delay, u16 *max_accepted_htlcs, u8 *channel_flags, u32 *locktime, u8 **shutdown_scriptpubkey) +bool fromwire_dualopend_got_offer(const tal_t *ctx, const void *p, struct channel_id *channel_id, struct amount_sat *opener_funding, struct amount_sat *dust_limit_satoshis, struct amount_msat *max_htlc_value_in_flight_msat, struct amount_msat *htlc_minimum_msat, u32 *feerate_per_kw_funding, u32 *feerate_per_kw_commitment, u16 *to_self_delay, u16 *max_accepted_htlcs, u8 *channel_flags, u32 *locktime, u8 **shutdown_scriptpubkey, struct amount_sat *requested_amt, u32 *lease_blockheight_start) { u16 shutdown_len; @@ -295,12 +297,14 @@ bool fromwire_dualopend_got_offer(const tal_t *ctx, const void *p, struct channe // 2nd case shutdown_scriptpubkey *shutdown_scriptpubkey = shutdown_len ? tal_arr(ctx, u8, shutdown_len) : NULL; fromwire_u8_array(&cursor, &plen, *shutdown_scriptpubkey, shutdown_len); + *requested_amt = fromwire_amount_sat(&cursor, &plen); + *lease_blockheight_start = fromwire_u32(&cursor, &plen); return cursor != NULL; } /* WIRE: DUALOPEND_GOT_OFFER_REPLY */ /* master->dualopend: reply back with our first funding info/contribs */ -u8 *towire_dualopend_got_offer_reply(const tal_t *ctx, struct amount_sat accepter_funding, const struct wally_psbt *psbt, const u8 *our_shutdown_scriptpubkey) +u8 *towire_dualopend_got_offer_reply(const tal_t *ctx, struct amount_sat accepter_funding, const struct wally_psbt *psbt, const u8 *our_shutdown_scriptpubkey, const struct lease_rates *lease_rates) { u16 shutdown_len = tal_count(our_shutdown_scriptpubkey); u8 *p = tal_arr(ctx, u8, 0); @@ -310,10 +314,16 @@ u8 *towire_dualopend_got_offer_reply(const tal_t *ctx, struct amount_sat accepte towire_wally_psbt(&p, psbt); towire_u16(&p, shutdown_len); towire_u8_array(&p, our_shutdown_scriptpubkey, shutdown_len); + if (!lease_rates) + towire_bool(&p, false); + else { + towire_bool(&p, true); + towire_lease_rates(&p, lease_rates); + } return memcheck(p, tal_count(p)); } -bool fromwire_dualopend_got_offer_reply(const tal_t *ctx, const void *p, struct amount_sat *accepter_funding, struct wally_psbt **psbt, u8 **our_shutdown_scriptpubkey) +bool fromwire_dualopend_got_offer_reply(const tal_t *ctx, const void *p, struct amount_sat *accepter_funding, struct wally_psbt **psbt, u8 **our_shutdown_scriptpubkey, struct lease_rates **lease_rates) { u16 shutdown_len; @@ -328,6 +338,12 @@ bool fromwire_dualopend_got_offer_reply(const tal_t *ctx, const void *p, struct // 2nd case our_shutdown_scriptpubkey *our_shutdown_scriptpubkey = shutdown_len ? tal_arr(ctx, u8, shutdown_len) : NULL; fromwire_u8_array(&cursor, &plen, *our_shutdown_scriptpubkey, shutdown_len); + if (!fromwire_bool(&cursor, &plen)) + *lease_rates = NULL; + else { + *lease_rates = tal(ctx, struct lease_rates); + fromwire_lease_rates(&cursor, &plen, *lease_rates); + } return cursor != NULL; } @@ -605,7 +621,7 @@ bool fromwire_dualopend_fail(const tal_t *ctx, const void *p, wirestring **reaso /* WIRE: DUALOPEND_OPENER_INIT */ /* master->dualopend: hello */ -u8 *towire_dualopend_opener_init(const tal_t *ctx, const struct wally_psbt *psbt, struct amount_sat funding_amount, const u8 *local_shutdown_scriptpubkey, u32 feerate_per_kw, u32 feerate_per_kw_funding, u8 channel_flags) +u8 *towire_dualopend_opener_init(const tal_t *ctx, const struct wally_psbt *psbt, struct amount_sat funding_amount, const u8 *local_shutdown_scriptpubkey, u32 feerate_per_kw, u32 feerate_per_kw_funding, u8 channel_flags, struct amount_sat requested_sats, u32 blockheight) { u16 local_shutdown_len = tal_count(local_shutdown_scriptpubkey); u8 *p = tal_arr(ctx, u8, 0); @@ -618,10 +634,12 @@ u8 *towire_dualopend_opener_init(const tal_t *ctx, const struct wally_psbt *psbt towire_u32(&p, feerate_per_kw); towire_u32(&p, feerate_per_kw_funding); towire_u8(&p, channel_flags); + towire_amount_sat(&p, requested_sats); + towire_u32(&p, blockheight); return memcheck(p, tal_count(p)); } -bool fromwire_dualopend_opener_init(const tal_t *ctx, const void *p, struct wally_psbt **psbt, struct amount_sat *funding_amount, u8 **local_shutdown_scriptpubkey, u32 *feerate_per_kw, u32 *feerate_per_kw_funding, u8 *channel_flags) +bool fromwire_dualopend_opener_init(const tal_t *ctx, const void *p, struct wally_psbt **psbt, struct amount_sat *funding_amount, u8 **local_shutdown_scriptpubkey, u32 *feerate_per_kw, u32 *feerate_per_kw_funding, u8 *channel_flags, struct amount_sat *requested_sats, u32 *blockheight) { u16 local_shutdown_len; @@ -639,6 +657,8 @@ bool fromwire_dualopend_opener_init(const tal_t *ctx, const void *p, struct wall *feerate_per_kw = fromwire_u32(&cursor, &plen); *feerate_per_kw_funding = fromwire_u32(&cursor, &plen); *channel_flags = fromwire_u8(&cursor, &plen); + *requested_sats = fromwire_amount_sat(&cursor, &plen); + *blockheight = fromwire_u32(&cursor, &plen); return cursor != NULL; } @@ -912,4 +932,4 @@ bool fromwire_dualopend_dev_memleak_reply(const void *p, bool *leak) *leak = fromwire_bool(&cursor, &plen); return cursor != NULL; } -// SHA256STAMP:0a1ed6e8461512630be3bb328083495d5c5f682c59dfb24561024ba8fa0d3b70 +// SHA256STAMP:e450d9832b4f8b8303a2f887e451d3e3964d1dfeff5cbe41762232a02bcaf13f diff --git a/openingd/dualopend_wiregen.h b/openingd/dualopend_wiregen.h index de36baf2f782..0c1e9c6527ef 100644 --- a/openingd/dualopend_wiregen.h +++ b/openingd/dualopend_wiregen.h @@ -18,6 +18,7 @@ #include #include #include +#include enum dualopend_wire { WIRE_DUALOPEND_INIT = 7000, @@ -96,13 +97,13 @@ bool fromwire_dualopend_reinit(const tal_t *ctx, const void *p, const struct cha /* WIRE: DUALOPEND_GOT_OFFER */ /* dualopend->master: they offered channel */ -u8 *towire_dualopend_got_offer(const tal_t *ctx, const struct channel_id *channel_id, struct amount_sat opener_funding, struct amount_sat dust_limit_satoshis, struct amount_msat max_htlc_value_in_flight_msat, struct amount_msat htlc_minimum_msat, u32 feerate_per_kw_funding, u32 feerate_per_kw_commitment, u16 to_self_delay, u16 max_accepted_htlcs, u8 channel_flags, u32 locktime, const u8 *shutdown_scriptpubkey); -bool fromwire_dualopend_got_offer(const tal_t *ctx, const void *p, struct channel_id *channel_id, struct amount_sat *opener_funding, struct amount_sat *dust_limit_satoshis, struct amount_msat *max_htlc_value_in_flight_msat, struct amount_msat *htlc_minimum_msat, u32 *feerate_per_kw_funding, u32 *feerate_per_kw_commitment, u16 *to_self_delay, u16 *max_accepted_htlcs, u8 *channel_flags, u32 *locktime, u8 **shutdown_scriptpubkey); +u8 *towire_dualopend_got_offer(const tal_t *ctx, const struct channel_id *channel_id, struct amount_sat opener_funding, struct amount_sat dust_limit_satoshis, struct amount_msat max_htlc_value_in_flight_msat, struct amount_msat htlc_minimum_msat, u32 feerate_per_kw_funding, u32 feerate_per_kw_commitment, u16 to_self_delay, u16 max_accepted_htlcs, u8 channel_flags, u32 locktime, const u8 *shutdown_scriptpubkey, struct amount_sat requested_amt, u32 lease_blockheight_start); +bool fromwire_dualopend_got_offer(const tal_t *ctx, const void *p, struct channel_id *channel_id, struct amount_sat *opener_funding, struct amount_sat *dust_limit_satoshis, struct amount_msat *max_htlc_value_in_flight_msat, struct amount_msat *htlc_minimum_msat, u32 *feerate_per_kw_funding, u32 *feerate_per_kw_commitment, u16 *to_self_delay, u16 *max_accepted_htlcs, u8 *channel_flags, u32 *locktime, u8 **shutdown_scriptpubkey, struct amount_sat *requested_amt, u32 *lease_blockheight_start); /* WIRE: DUALOPEND_GOT_OFFER_REPLY */ /* master->dualopend: reply back with our first funding info/contribs */ -u8 *towire_dualopend_got_offer_reply(const tal_t *ctx, struct amount_sat accepter_funding, const struct wally_psbt *psbt, const u8 *our_shutdown_scriptpubkey); -bool fromwire_dualopend_got_offer_reply(const tal_t *ctx, const void *p, struct amount_sat *accepter_funding, struct wally_psbt **psbt, u8 **our_shutdown_scriptpubkey); +u8 *towire_dualopend_got_offer_reply(const tal_t *ctx, struct amount_sat accepter_funding, const struct wally_psbt *psbt, const u8 *our_shutdown_scriptpubkey, const struct lease_rates *lease_rates); +bool fromwire_dualopend_got_offer_reply(const tal_t *ctx, const void *p, struct amount_sat *accepter_funding, struct wally_psbt **psbt, u8 **our_shutdown_scriptpubkey, struct lease_rates **lease_rates); /* WIRE: DUALOPEND_GOT_RBF_OFFER */ /* dualopend->master: they offered a RBF */ @@ -152,8 +153,8 @@ bool fromwire_dualopend_fail(const tal_t *ctx, const void *p, wirestring **reaso /* WIRE: DUALOPEND_OPENER_INIT */ /* master->dualopend: hello */ -u8 *towire_dualopend_opener_init(const tal_t *ctx, const struct wally_psbt *psbt, struct amount_sat funding_amount, const u8 *local_shutdown_scriptpubkey, u32 feerate_per_kw, u32 feerate_per_kw_funding, u8 channel_flags); -bool fromwire_dualopend_opener_init(const tal_t *ctx, const void *p, struct wally_psbt **psbt, struct amount_sat *funding_amount, u8 **local_shutdown_scriptpubkey, u32 *feerate_per_kw, u32 *feerate_per_kw_funding, u8 *channel_flags); +u8 *towire_dualopend_opener_init(const tal_t *ctx, const struct wally_psbt *psbt, struct amount_sat funding_amount, const u8 *local_shutdown_scriptpubkey, u32 feerate_per_kw, u32 feerate_per_kw_funding, u8 channel_flags, struct amount_sat requested_sats, u32 blockheight); +bool fromwire_dualopend_opener_init(const tal_t *ctx, const void *p, struct wally_psbt **psbt, struct amount_sat *funding_amount, u8 **local_shutdown_scriptpubkey, u32 *feerate_per_kw, u32 *feerate_per_kw_funding, u8 *channel_flags, struct amount_sat *requested_sats, u32 *blockheight); /* WIRE: DUALOPEND_FUNDING_SIGS */ /* dualopend->master received tx_sigs from peer */ @@ -216,4 +217,4 @@ bool fromwire_dualopend_dev_memleak_reply(const void *p, bool *leak); #endif /* LIGHTNING_OPENINGD_DUALOPEND_WIREGEN_H */ -// SHA256STAMP:0a1ed6e8461512630be3bb328083495d5c5f682c59dfb24561024ba8fa0d3b70 +// SHA256STAMP:e450d9832b4f8b8303a2f887e451d3e3964d1dfeff5cbe41762232a02bcaf13f From 7ec2d652884624cf2d3fa33b868c7604c8c0347b Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 8 Jun 2021 16:55:06 -0500 Subject: [PATCH 18/56] liquidity-ad: pipe `request_amt` all the way out to fundchannel Changelog-Added: JSON-RPC: `fundchannel` now takes optional `request_amt` parameter --- contrib/pyln-client/pyln/client/lightning.py | 7 ++++++- doc/lightning-fundchannel.7 | 8 ++++++-- doc/lightning-fundchannel.7.md | 6 +++++- doc/lightning-multifundchannel.7 | 6 +++++- doc/lightning-multifundchannel.7.md | 3 +++ plugins/spender/fundchannel.c | 4 ++++ plugins/spender/multifundchannel.c | 5 ++++- plugins/spender/multifundchannel.h | 3 +++ plugins/spender/openchannel.c | 5 +++++ 9 files changed, 41 insertions(+), 6 deletions(-) diff --git a/contrib/pyln-client/pyln/client/lightning.py b/contrib/pyln-client/pyln/client/lightning.py index 3df040ad1cca..7c11c2c9525f 100644 --- a/contrib/pyln-client/pyln/client/lightning.py +++ b/contrib/pyln-client/pyln/client/lightning.py @@ -693,7 +693,7 @@ def feerates(self, style, urgent=None, normal=None, slow=None): } return self.call("feerates", payload) - def fundchannel(self, node_id, amount, feerate=None, announce=True, minconf=None, utxos=None, push_msat=None, close_to=None): + def fundchannel(self, node_id, amount, feerate=None, announce=True, minconf=None, utxos=None, push_msat=None, close_to=None, request_amt=None): """ Fund channel with {id} using {amount} satoshis with feerate of {feerate} (uses default feerate if unset). @@ -702,6 +702,10 @@ def fundchannel(self, node_id, amount, feerate=None, announce=True, minconf=None If {utxos} is specified (as a list of 'txid:vout' strings), fund a channel from these specifics utxos. {close_to} is a valid Bitcoin address. + + {request_amt} is the lease amount to request from the peer. Only + valid if peer is advertising a liquidity ad + supports v2 channel opens + (dual-funding) """ payload = { "id": node_id, @@ -712,6 +716,7 @@ def fundchannel(self, node_id, amount, feerate=None, announce=True, minconf=None "utxos": utxos, "push_msat": push_msat, "close_to": close_to, + "request_amt": request_amt, } return self.call("fundchannel", payload) diff --git a/doc/lightning-fundchannel.7 b/doc/lightning-fundchannel.7 index 69944ba73735..91cc2203ce59 100644 --- a/doc/lightning-fundchannel.7 +++ b/doc/lightning-fundchannel.7 @@ -72,6 +72,11 @@ on close\. Only valid if both peers have negotiated \fBoption_upfront_shutdown_s Returns \fBclose_to\fR set to closing script iff is negotiated\. +\fIrequest_amt\fR is an amount of liquidity you'd like to lease from the peer\. +If peer supports \fBoption_will_fund\fR, indicates to them to include this +much liquidity into the channel\. + + This example shows how to use lightning-cli to open new channel with peer 03f\.\.\.fc1 from one whole utxo bcc1\.\.\.39c:0 (you can use \fBlistfunds\fR command to get txid and vout): @@ -80,7 +85,6 @@ This example shows how to use lightning-cli to open new channel with peer 03f\.\ lightning-cli -k fundchannel id=03f...fc1 amount=all feerate=normal utxos='["bcc1...39c:0"]' - .RE .fi @@ -130,4 +134,4 @@ channel parameters (funding limits, channel reserves, fees, etc\.)\. Main web site: \fIhttps://github.com/ElementsProject/lightning\fR -\" SHA256STAMP:ee8d7d247d9d4f263f8bbed936a2ba4b61d4afc5c48580f462a0d6142c13dbbd +\" SHA256STAMP:f26c502b7c8da644606d64e08451732652b56e9182e16fa42fa2b3224fe5f9d4 diff --git a/doc/lightning-fundchannel.7.md b/doc/lightning-fundchannel.7.md index deaa3904e8c8..d8446e6322b7 100644 --- a/doc/lightning-fundchannel.7.md +++ b/doc/lightning-fundchannel.7.md @@ -64,12 +64,16 @@ unrecoverable once pushed. on close. Only valid if both peers have negotiated `option_upfront_shutdown_script`. Returns `close_to` set to closing script iff is negotiated. +*request_amt* is an amount of liquidity you'd like to lease from the peer. +If peer supports `option_will_fund`, indicates to them to include this +much liquidity into the channel. + + This example shows how to use lightning-cli to open new channel with peer 03f...fc1 from one whole utxo bcc1...39c:0 (you can use **listfunds** command to get txid and vout): lightning-cli -k fundchannel id=03f...fc1 amount=all feerate=normal utxos='["bcc1...39c:0"]' - RETURN VALUE ------------ diff --git a/doc/lightning-multifundchannel.7 b/doc/lightning-multifundchannel.7 index a626ef63f926..72289b042e44 100644 --- a/doc/lightning-multifundchannel.7 +++ b/doc/lightning-multifundchannel.7 @@ -58,6 +58,10 @@ out of this\. on close\. Only valid if both peers have negotiated \fBoption_upfront_shutdown_script\fR\. Returns \fBclose_to\fR set to closing script iff is negotiated\. +.IP \[bu] +\fIrequest_amt\fR is the amount of liquidity you'd like to lease from peer\. +If peer supports \fBoption_will_fund\fR, indicates to them to include this +much liquidity into the channel\. .RE @@ -177,4 +181,4 @@ ZmnSCPxj \fI is mainly responsible\. Main web site: \fIhttps://github.com/ElementsProject/lightning\fR -\" SHA256STAMP:45015c53c73dc4d84850c84cb753d62739288365746b47f0403fb67e5f65d582 +\" SHA256STAMP:d9a15c4547808d6e7fb1df0e9d1c4183c99ba2caa664c3b7bbb0dcfd15c4256c diff --git a/doc/lightning-multifundchannel.7.md b/doc/lightning-multifundchannel.7.md index 07b7307c8ade..eb95af563959 100644 --- a/doc/lightning-multifundchannel.7.md +++ b/doc/lightning-multifundchannel.7.md @@ -51,6 +51,9 @@ Readiness is indicated by **listpeers** reporting a *state* of on close. Only valid if both peers have negotiated `option_upfront_shutdown_script`. Returns `close_to` set to closing script iff is negotiated. +* *request_amt* is the amount of liquidity you'd like to lease from peer. +If peer supports `option_will_fund`, indicates to them to include this +much liquidity into the channel. There must be at least one entry in *destinations*; it cannot be an empty array. diff --git a/plugins/spender/fundchannel.c b/plugins/spender/fundchannel.c index 39cdae088e81..e4b75756dea8 100644 --- a/plugins/spender/fundchannel.c +++ b/plugins/spender/fundchannel.c @@ -42,6 +42,7 @@ json_fundchannel(struct command *cmd, const jsmntok_t *utxos; const jsmntok_t *push_msat; const jsmntok_t *close_to; + const jsmntok_t *request_amt; struct out_req *req; @@ -54,6 +55,7 @@ json_fundchannel(struct command *cmd, p_opt("utxos", param_tok, &utxos), p_opt("push_msat", param_tok, &push_msat), p_opt("close_to", param_tok, &close_to), + p_opt("request_amt", param_tok, &request_amt), NULL)) return command_param_failed(); @@ -71,6 +73,8 @@ json_fundchannel(struct command *cmd, json_add_tok(req->js, "push_msat", push_msat, buf); if (close_to) json_add_tok(req->js, "close_to", close_to, buf); + if (request_amt) + json_add_tok(req->js, "request_amt", request_amt, buf); json_object_end(req->js); json_array_end(req->js); if (feerate) diff --git a/plugins/spender/multifundchannel.c b/plugins/spender/multifundchannel.c index 72fbe4e8cacf..6df6931b6f27 100644 --- a/plugins/spender/multifundchannel.c +++ b/plugins/spender/multifundchannel.c @@ -1813,7 +1813,7 @@ param_destinations_array(struct command *cmd, const char *name, struct multifundchannel_destination *dest; const char *id; char *addrhint; - struct amount_sat *amount; + struct amount_sat *amount, *request_amt; bool *announce; struct amount_msat *push_msat; @@ -1830,6 +1830,8 @@ param_destinations_array(struct command *cmd, const char *name, * passed in to fundchannel_start) if invalid*/ p_opt("close_to", param_string, &dest->close_to_str), + p_opt_def("request_amt", param_sat, &request_amt, + AMOUNT_SAT(0)), NULL)) return command_param_failed(); @@ -1864,6 +1866,7 @@ param_destinations_array(struct command *cmd, const char *name, dest->psbt = NULL; dest->updated_psbt = NULL; dest->protocol = FUND_CHANNEL; + dest->request_amt = *request_amt; /* Only one destination can have "all" indicator. */ if (dest->all) { diff --git a/plugins/spender/multifundchannel.h b/plugins/spender/multifundchannel.h index 1519ccfa105c..0a1614ce4fe7 100644 --- a/plugins/spender/multifundchannel.h +++ b/plugins/spender/multifundchannel.h @@ -143,6 +143,9 @@ struct multifundchannel_destination { /* serial of the funding output for this channel (OPEN_CHANNEL) */ u64 funding_serial; + + /* amount to request peer to lease (OPEN_CHANNEL) */ + struct amount_sat request_amt; }; diff --git a/plugins/spender/openchannel.c b/plugins/spender/openchannel.c index 43deb9beed10..9f274aad74df 100644 --- a/plugins/spender/openchannel.c +++ b/plugins/spender/openchannel.c @@ -1025,6 +1025,11 @@ openchannel_init_dest(struct multifundchannel_destination *dest) type_to_string(tmpctx, struct amount_msat, &dest->push_msat)); + /* Request some sats from the peer! */ + if (amount_sat_greater(dest->request_amt, AMOUNT_SAT(0))) + json_add_string(req->js, "request_amt", + fmt_amount_sat(tmpctx, dest->request_amt)); + return send_outreq(cmd->plugin, req); } From 91ea47166cd97238729e14642eb8ce5773945a24 Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 8 Jun 2021 16:56:07 -0500 Subject: [PATCH 19/56] liquidity-ad: fill in acceptance response Asks HSMD for signed lease termsheet, fills in the details to the accept_channel2 TLV --- lightningd/dual_open_control.c | 6 ++-- openingd/dualopend.c | 57 ++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index f7779f282a72..da29189d1ea5 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -2878,7 +2878,8 @@ static void start_fresh_dualopend(struct peer *peer, hsmfd = hsm_get_client_fd(peer->ld, &peer->id, channel->unsaved_dbid, HSM_CAP_COMMITMENT_POINT - | HSM_CAP_SIGN_REMOTE_TX); + | HSM_CAP_SIGN_REMOTE_TX + | HSM_CAP_SIGN_WILL_FUND_OFFER); channel->owner = new_channel_subd(peer->ld, "lightning_dualopend", @@ -2944,7 +2945,8 @@ void peer_restart_dualopend(struct peer *peer, } hsmfd = hsm_get_client_fd(peer->ld, &peer->id, channel->dbid, HSM_CAP_COMMITMENT_POINT - | HSM_CAP_SIGN_REMOTE_TX); + | HSM_CAP_SIGN_REMOTE_TX + | HSM_CAP_SIGN_WILL_FUND_OFFER); channel_set_owner(channel, new_channel_subd(peer->ld, "lightning_dualopend", diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 21a6bc50beaa..662a0a566068 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -1879,6 +1879,51 @@ static u8 *accepter_commits(struct state *state, return msg; } +static void accept_tlv_add_offer(struct tlv_accept_tlvs *a_tlv, + struct lease_rates *rates, + struct pubkey funding_pubkey, + u32 blockheight) +{ + secp256k1_ecdsa_signature ad_sig; + u8 *msg; + + /* Go get the signature for this lease offer from HSMD */ + msg = towire_hsmd_sign_option_will_fund_offer(NULL, + &funding_pubkey, + blockheight, + rates->channel_fee_max_base_msat, + rates->channel_fee_max_proportional_thousandths); + if (!wire_sync_write(HSM_FD, take(msg))) + status_failed(STATUS_FAIL_HSM_IO, + "Could not write to HSM: %s", + strerror(errno)); + msg = wire_sync_read(tmpctx, HSM_FD); + if (!fromwire_hsmd_sign_option_will_fund_offer_reply(msg, &ad_sig)) + status_failed(STATUS_FAIL_HSM_IO, + "Bad sign_option_will_fund_offer_reply %s", + tal_hex(tmpctx, msg)); + + /* BOLT- #2: + * The accepting node: + * ... + * - MUST set `funding_fee_base_sat` to the base fee + * (in satoshi) it will charge for the `funding_satoshis` + * - MUST set `funding_fee_proportional_basis` to the amount + * (in thousandths of satoshi) it will charge per `funding_satoshi` + * - MUST set `funding_weight` to the weight they + * will contribute to this channel, to fund the request. + * - MUST set `channel_fee_base_max_msat` to the base fee + * (in millisatoshi) it will charge for any HTLC on this channel + * during the funding period. + * - MUST set `channel_fee_proportional_basis_max` to the amount + * (in thousandths of a satoshi) it will charge per transferred + * satoshi during the funding period. + */ + a_tlv->will_fund = tal(a_tlv, struct tlv_accept_tlvs_will_fund); + a_tlv->will_fund->lease_rates = *rates; + a_tlv->will_fund->signature = ad_sig; +} + static void accepter_start(struct state *state, const u8 *oc2_msg) { struct bitcoin_blkid chain_hash; @@ -2106,6 +2151,18 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) 0); } + /* BOLT- #2: + * The accepting node: + * ... + * - if the `option_will_fund` tlv was sent in `open_channel2`: + * - if they decide to accept the offer: + * - MUST include a `will_fund` tlv + */ + if (open_tlv->request_funds && tx_state->rates) + accept_tlv_add_offer(a_tlv, tx_state->rates, + state->our_funding_pubkey, + lease_blockheight_start); + msg = towire_accept_channel2(tmpctx, &state->channel_id, tx_state->accepter_funding, tx_state->localconf.dust_limit, From 3b90c5b81a3c30b230c22dc8fddf0c4f36ca58a2 Mon Sep 17 00:00:00 2001 From: niftynei Date: Fri, 11 Jun 2021 16:34:49 -0500 Subject: [PATCH 20/56] dualopend, openchannel_init: pull out feerate parsing logic we'll use it again here shortly --- lightningd/dual_open_control.c | 47 ++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index da29189d1ea5..307b3a9e7c1f 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -2316,10 +2316,33 @@ static struct command_result *json_openchannel_update(struct command *cmd, return command_still_pending(cmd); } +static struct command_result *init_set_feerate(struct command *cmd, + u32 **feerate_per_kw, + u32 **feerate_per_kw_funding) + +{ + if (!*feerate_per_kw_funding) { + *feerate_per_kw_funding = tal(cmd, u32); + **feerate_per_kw_funding = opening_feerate(cmd->ld->topology); + if (!**feerate_per_kw_funding) + return command_fail(cmd, LIGHTNINGD, + "`funding_feerate` not specified and fee " + "estimation failed"); + } + if (!*feerate_per_kw) { + *feerate_per_kw = tal(cmd, u32); + /* FIXME: Anchors are on by default, we should use the lowest + * possible feerate */ + **feerate_per_kw = **feerate_per_kw_funding; + } + + return NULL; +} + static struct command_result *json_openchannel_init(struct command *cmd, - const char *buffer, - const jsmntok_t *obj UNNEEDED, - const jsmntok_t *params) + const char *buffer, + const jsmntok_t *obj UNNEEDED, + const jsmntok_t *params) { struct node_id *id; struct peer *peer; @@ -2331,6 +2354,7 @@ static struct command_result *json_openchannel_init(struct command *cmd, struct wally_psbt *psbt; const u8 *our_upfront_shutdown_script; struct open_attempt *oa; + struct command_result *res; u8 *msg; if (!param(cmd, buffer, params, @@ -2370,20 +2394,9 @@ static struct command_result *json_openchannel_init(struct command *cmd, struct wally_psbt, psbt)); - if (!feerate_per_kw_funding) { - feerate_per_kw_funding = tal(cmd, u32); - *feerate_per_kw_funding = opening_feerate(cmd->ld->topology); - if (!*feerate_per_kw_funding) - return command_fail(cmd, LIGHTNINGD, - "`funding_feerate` not specified and fee " - "estimation failed"); - } - if (!feerate_per_kw) { - feerate_per_kw = tal(cmd, u32); - /* FIXME: Anchors are on by default, we should use the lowest - * possible feerate */ - *feerate_per_kw = *feerate_per_kw_funding; - } + res = init_set_feerate(cmd, &feerate_per_kw, &feerate_per_kw_funding); + if (res) + return res; if (!topology_synced(cmd->ld->topology)) { return command_fail(cmd, FUNDING_STILL_SYNCING_BITCOIN, From 414dafd806631d78382e7e59a2a40aa60c779501 Mon Sep 17 00:00:00 2001 From: niftynei Date: Fri, 11 Jun 2021 16:32:27 -0500 Subject: [PATCH 21/56] rpc: add queryrates Undocumented RPC call for asking a peer what their rates are --- contrib/pyln-client/pyln/client/lightning.py | 11 ++ lightningd/dual_open_control.c | 151 ++++++++++++++++++- openingd/dualopend.c | 31 +++- openingd/dualopend_wire.csv | 8 + openingd/dualopend_wiregen.c | 48 +++++- openingd/dualopend_wiregen.h | 13 +- tests/test_opening.py | 39 ++++- 7 files changed, 291 insertions(+), 10 deletions(-) diff --git a/contrib/pyln-client/pyln/client/lightning.py b/contrib/pyln-client/pyln/client/lightning.py index 7c11c2c9525f..63c919a4c467 100644 --- a/contrib/pyln-client/pyln/client/lightning.py +++ b/contrib/pyln-client/pyln/client/lightning.py @@ -1011,6 +1011,17 @@ def pay(self, bolt11, msatoshi=None, label=None, riskfactor=None, } return self.call("pay", payload) + def queryrates(self, node_id, channel_amount, request_amt, commitment_feerate=None, funding_feerate=None): + """Ask a peer how much they'd charge for a given liquidity amount """ + payload = { + "id": node_id, + "amount": channel_amount, + "request_amt": request_amt, + "commitment_feerate": commitment_feerate, + "funding_feerate": funding_feerate, + } + return self.call("queryrates", payload) + def openchannel_init(self, node_id, channel_amount, psbt, feerate=None, funding_feerate=None, announce=True, close_to=None, request_amt=None, *args, **kwargs): """Initiate an openchannel with a peer """ payload = { diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index 307b3a9e7c1f..b26b41b428ec 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -1542,6 +1542,43 @@ static void handle_peer_tx_sigs_sent(struct subd *dualopend, } } +static void handle_dry_run_finished(struct subd *dualopend, const u8 *msg) +{ + struct json_stream *response; + struct channel_id c_id; + struct channel *channel = dualopend->channel; + struct command *cmd; + struct lease_rates *rates; + struct amount_sat their_funding, our_funding; + + assert(channel->open_attempt); + cmd = channel->open_attempt->cmd; + channel->open_attempt->cmd = NULL; + + if (!fromwire_dualopend_dry_run(msg, msg, &c_id, + &our_funding, + &their_funding, + &rates)) { + channel_internal_error(channel, + "Bad WIRE_DUALOPEND_DRY_RUN_FINISHED: %s", + tal_hex(msg, msg)); + + return; + } + + /* Free up this open attempt */ + channel->open_attempt = tal_free(channel->open_attempt); + + response = json_stream_success(cmd); + json_add_amount_sat_only(response, "our_funding_msat", our_funding); + json_add_amount_sat_only(response, "their_funding_msat", their_funding); + + if (rates) + json_add_lease_rates(response, rates); + + was_pending(command_success(cmd, response)); +} + static void handle_peer_locked(struct subd *dualopend, const u8 *msg) { struct pubkey remote_per_commit; @@ -2339,6 +2376,105 @@ static struct command_result *init_set_feerate(struct command *cmd, return NULL; } +static struct command_result *json_queryrates(struct command *cmd, + const char *buffer, + const jsmntok_t *obj UNNEEDED, + const jsmntok_t *params) +{ + struct node_id *id; + struct peer *peer; + struct channel *channel; + u32 *feerate_per_kw_funding; + u32 *feerate_per_kw; + struct amount_sat *amount, *request_amt; + struct wally_psbt *psbt; + struct open_attempt *oa; + u8 *msg; + struct command_result *res; + + if (!param(cmd, buffer, params, + p_req("id", param_node_id, &id), + p_req("amount", param_sat, &amount), + p_req("request_amt", param_sat, &request_amt), + p_opt("commitment_feerate", param_feerate, &feerate_per_kw), + p_opt("funding_feerate", param_feerate, &feerate_per_kw_funding), + NULL)) + return command_param_failed(); + + res = init_set_feerate(cmd, &feerate_per_kw, &feerate_per_kw_funding); + if (res) + return res; + + peer = peer_by_id(cmd->ld, id); + if (!peer) { + return command_fail(cmd, FUNDING_UNKNOWN_PEER, "Unknown peer"); + } + + /* We can't query rates for a peer we have a channel with */ + channel = peer_active_channel(peer); + if (channel) + return command_fail(cmd, LIGHTNINGD, "Peer in state %s," + " can't query peer's rates if already" + " have a channel", + channel_state_name(channel)); + + channel = peer_unsaved_channel(peer); + if (!channel || !channel->owner) + return command_fail(cmd, FUNDING_PEER_NOT_CONNECTED, + "Peer not connected"); + if (channel->open_attempt + || !list_empty(&channel->inflights)) + return command_fail(cmd, FUNDING_STATE_INVALID, + "Channel funding in-progress. %s", + channel_state_name(channel)); + + if (!feature_negotiated(cmd->ld->our_features, + peer->their_features, + OPT_DUAL_FUND)) { + return command_fail(cmd, FUNDING_V2_NOT_SUPPORTED, + "v2 openchannel not supported " + "by peer, can't query rates"); + } + + /* BOLT #2: + * - if both nodes advertised `option_support_large_channel`: + * - MAY set `funding_satoshis` greater than or equal to 2^24 satoshi. + * - otherwise: + * - MUST set `funding_satoshis` to less than 2^24 satoshi. + */ + if (!feature_negotiated(cmd->ld->our_features, + peer->their_features, OPT_LARGE_CHANNELS) + && amount_sat_greater(*amount, chainparams->max_funding)) + return command_fail(cmd, FUND_MAX_EXCEEDED, + "Amount exceeded %s", + type_to_string(tmpctx, struct amount_sat, + &chainparams->max_funding)); + + /* Get a new open_attempt going, keeps us from re-initing + * while looking */ + channel->opener = LOCAL; + channel->open_attempt = oa = new_channel_open_attempt(channel); + channel->channel_flags = OUR_CHANNEL_FLAGS; + oa->funding = *amount; + oa->cmd = cmd; + /* empty psbt to start */ + psbt = create_psbt(tmpctx, 0, 0, 0); + + msg = towire_dualopend_opener_init(NULL, + psbt, *amount, + oa->our_upfront_shutdown_script, + *feerate_per_kw, + *feerate_per_kw_funding, + channel->channel_flags, + *request_amt, + get_block_height(cmd->ld->topology), + true); + + subd_send_msg(channel->owner, take(msg)); + return command_still_pending(cmd); + +} + static struct command_result *json_openchannel_init(struct command *cmd, const char *buffer, const jsmntok_t *obj UNNEEDED, @@ -2488,7 +2624,8 @@ static struct command_result *json_openchannel_init(struct command *cmd, *feerate_per_kw_funding, channel->channel_flags, *request_amt, - get_block_height(cmd->ld->topology)); + get_block_height(cmd->ld->topology), + false); subd_send_msg(channel->owner, take(msg)); return command_still_pending(cmd); @@ -2782,6 +2919,9 @@ static unsigned int dual_opend_msg(struct subd *dualopend, case WIRE_DUALOPEND_PEER_LOCKED: handle_peer_locked(dualopend, msg); return 0; + case WIRE_DUALOPEND_DRY_RUN: + handle_dry_run_finished(dualopend, msg); + return 0; case WIRE_DUALOPEND_CHANNEL_LOCKED: if (tal_count(fds) != 3) return 3; @@ -2836,6 +2976,14 @@ static unsigned int dual_opend_msg(struct subd *dualopend, return 0; } +static const struct json_command queryrates_command = { + "queryrates", + "channels", + json_queryrates, + "Ask a peer what their contribution and liquidity rates are" + " for the given {amount} and {requested_amt}" +}; + static const struct json_command openchannel_init_command = { "openchannel_init", "channels", @@ -2874,6 +3022,7 @@ static const struct json_command openchannel_abort_command = { "Abort {channel_id}'s open. Usable while `commitment_signed=false`." }; +AUTODATA(json_command, &queryrates_command); AUTODATA(json_command, &openchannel_init_command); AUTODATA(json_command, &openchannel_update_command); AUTODATA(json_command, &openchannel_signed_command); diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 662a0a566068..1ccbbc01227a 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -1979,7 +1979,6 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) lease_blockheight_start = 0; } - /* BOLT-* #2 * If the peer's revocation basepoint is unknown (e.g. * `open_channel2`), a temporary `channel_id` should be found @@ -2470,6 +2469,7 @@ static void opener_start(struct state *state, u8 *msg) char *err_reason; struct amount_sat total, requested_sats; u32 current_blockheight; + bool dry_run; struct tx_state *tx_state = state->tx_state; if (!fromwire_dualopend_opener_init(state, msg, @@ -2480,7 +2480,8 @@ static void opener_start(struct state *state, u8 *msg) &state->feerate_per_kw_funding, &state->channel_flags, &requested_sats, - ¤t_blockheight)) + ¤t_blockheight, + &dry_run)) master_badmsg(WIRE_DUALOPEND_OPENER_INIT, msg); state->our_role = TX_INITIATOR; @@ -2599,6 +2600,31 @@ static void opener_start(struct state *state, u8 *msg) &state->our_points.revocation, &state->their_points.revocation); + /* If this is a dry run, we just wanted to know + * how much they'd put into the channel and their terms */ + if (dry_run) { + msg = towire_dualopend_dry_run(NULL, &state->channel_id, + tx_state->opener_funding, + tx_state->accepter_funding, + a_tlv->will_fund + ? &a_tlv->will_fund->lease_rates : NULL); + + + wire_sync_write(REQ_FD, take(msg)); + + /* Note that this *normally* would return an error + * to the RPC caller. We head this off by + * sending a message to master just before this, + * which works as expected as long as + * these messages are queued+processed sequentially */ + open_err_warn(state, "%s", "Abort requested"); + } + + /* FIXME: BOLT QUOTE */ + if (open_tlv->request_funds && a_tlv->will_fund) { + /* OK! lease mode activated */ + } + /* Check that total funding doesn't overflow */ if (!amount_sat_add(&total, tx_state->opener_funding, tx_state->accepter_funding)) @@ -3392,6 +3418,7 @@ static u8 *handle_master_in(struct state *state) case WIRE_DUALOPEND_GOT_SHUTDOWN: case WIRE_DUALOPEND_SHUTDOWN_COMPLETE: case WIRE_DUALOPEND_FAIL_FALLEN_BEHIND: + case WIRE_DUALOPEND_DRY_RUN: break; } diff --git a/openingd/dualopend_wire.csv b/openingd/dualopend_wire.csv index 9f1343f1ed0f..554a8162878c 100644 --- a/openingd/dualopend_wire.csv +++ b/openingd/dualopend_wire.csv @@ -167,6 +167,7 @@ msgdata,dualopend_opener_init,feerate_per_kw_funding,u32, msgdata,dualopend_opener_init,channel_flags,u8, msgdata,dualopend_opener_init,requested_sats,amount_sat, msgdata,dualopend_opener_init,blockheight,u32, +msgdata,dualopend_opener_init,dry_run,bool, # dualopend->master received tx_sigs from peer msgtype,dualopend_funding_sigs,7010 @@ -213,3 +214,10 @@ msgtype,dualopend_dev_memleak,7033 msgtype,dualopend_dev_memleak_reply,7133 msgdata,dualopend_dev_memleak_reply,leak,bool, + +# dualopend -> master: this was a dry run, here's some info about this open +msgtype,dualopend_dry_run,7026 +msgdata,dualopend_dry_run,channel_id,channel_id, +msgdata,dualopend_dry_run,our_funding,amount_sat, +msgdata,dualopend_dry_run,their_funding,amount_sat, +msgdata,dualopend_dry_run,lease_rates,?lease_rates, diff --git a/openingd/dualopend_wiregen.c b/openingd/dualopend_wiregen.c index 85d9025aa7e0..0ab4110fee90 100644 --- a/openingd/dualopend_wiregen.c +++ b/openingd/dualopend_wiregen.c @@ -46,6 +46,7 @@ const char *dualopend_wire_name(int e) case WIRE_DUALOPEND_SHUTDOWN_COMPLETE: return "WIRE_DUALOPEND_SHUTDOWN_COMPLETE"; case WIRE_DUALOPEND_DEV_MEMLEAK: return "WIRE_DUALOPEND_DEV_MEMLEAK"; case WIRE_DUALOPEND_DEV_MEMLEAK_REPLY: return "WIRE_DUALOPEND_DEV_MEMLEAK_REPLY"; + case WIRE_DUALOPEND_DRY_RUN: return "WIRE_DUALOPEND_DRY_RUN"; } snprintf(invalidbuf, sizeof(invalidbuf), "INVALID %i", e); @@ -81,6 +82,7 @@ bool dualopend_wire_is_defined(u16 type) case WIRE_DUALOPEND_SHUTDOWN_COMPLETE:; case WIRE_DUALOPEND_DEV_MEMLEAK:; case WIRE_DUALOPEND_DEV_MEMLEAK_REPLY:; + case WIRE_DUALOPEND_DRY_RUN:; return true; } return false; @@ -621,7 +623,7 @@ bool fromwire_dualopend_fail(const tal_t *ctx, const void *p, wirestring **reaso /* WIRE: DUALOPEND_OPENER_INIT */ /* master->dualopend: hello */ -u8 *towire_dualopend_opener_init(const tal_t *ctx, const struct wally_psbt *psbt, struct amount_sat funding_amount, const u8 *local_shutdown_scriptpubkey, u32 feerate_per_kw, u32 feerate_per_kw_funding, u8 channel_flags, struct amount_sat requested_sats, u32 blockheight) +u8 *towire_dualopend_opener_init(const tal_t *ctx, const struct wally_psbt *psbt, struct amount_sat funding_amount, const u8 *local_shutdown_scriptpubkey, u32 feerate_per_kw, u32 feerate_per_kw_funding, u8 channel_flags, struct amount_sat requested_sats, u32 blockheight, bool dry_run) { u16 local_shutdown_len = tal_count(local_shutdown_scriptpubkey); u8 *p = tal_arr(ctx, u8, 0); @@ -636,10 +638,11 @@ u8 *towire_dualopend_opener_init(const tal_t *ctx, const struct wally_psbt *psbt towire_u8(&p, channel_flags); towire_amount_sat(&p, requested_sats); towire_u32(&p, blockheight); + towire_bool(&p, dry_run); return memcheck(p, tal_count(p)); } -bool fromwire_dualopend_opener_init(const tal_t *ctx, const void *p, struct wally_psbt **psbt, struct amount_sat *funding_amount, u8 **local_shutdown_scriptpubkey, u32 *feerate_per_kw, u32 *feerate_per_kw_funding, u8 *channel_flags, struct amount_sat *requested_sats, u32 *blockheight) +bool fromwire_dualopend_opener_init(const tal_t *ctx, const void *p, struct wally_psbt **psbt, struct amount_sat *funding_amount, u8 **local_shutdown_scriptpubkey, u32 *feerate_per_kw, u32 *feerate_per_kw_funding, u8 *channel_flags, struct amount_sat *requested_sats, u32 *blockheight, bool *dry_run) { u16 local_shutdown_len; @@ -659,6 +662,7 @@ bool fromwire_dualopend_opener_init(const tal_t *ctx, const void *p, struct wall *channel_flags = fromwire_u8(&cursor, &plen); *requested_sats = fromwire_amount_sat(&cursor, &plen); *blockheight = fromwire_u32(&cursor, &plen); + *dry_run = fromwire_bool(&cursor, &plen); return cursor != NULL; } @@ -932,4 +936,42 @@ bool fromwire_dualopend_dev_memleak_reply(const void *p, bool *leak) *leak = fromwire_bool(&cursor, &plen); return cursor != NULL; } -// SHA256STAMP:e450d9832b4f8b8303a2f887e451d3e3964d1dfeff5cbe41762232a02bcaf13f + +/* WIRE: DUALOPEND_DRY_RUN */ +/* dualopend -> master: this was a dry run */ +u8 *towire_dualopend_dry_run(const tal_t *ctx, const struct channel_id *channel_id, struct amount_sat our_funding, struct amount_sat their_funding, const struct lease_rates *lease_rates) +{ + u8 *p = tal_arr(ctx, u8, 0); + + towire_u16(&p, WIRE_DUALOPEND_DRY_RUN); + towire_channel_id(&p, channel_id); + towire_amount_sat(&p, our_funding); + towire_amount_sat(&p, their_funding); + if (!lease_rates) + towire_bool(&p, false); + else { + towire_bool(&p, true); + towire_lease_rates(&p, lease_rates); + } + + return memcheck(p, tal_count(p)); +} +bool fromwire_dualopend_dry_run(const tal_t *ctx, const void *p, struct channel_id *channel_id, struct amount_sat *our_funding, struct amount_sat *their_funding, struct lease_rates **lease_rates) +{ + const u8 *cursor = p; + size_t plen = tal_count(p); + + if (fromwire_u16(&cursor, &plen) != WIRE_DUALOPEND_DRY_RUN) + return false; + fromwire_channel_id(&cursor, &plen, channel_id); + *our_funding = fromwire_amount_sat(&cursor, &plen); + *their_funding = fromwire_amount_sat(&cursor, &plen); + if (!fromwire_bool(&cursor, &plen)) + *lease_rates = NULL; + else { + *lease_rates = tal(ctx, struct lease_rates); + fromwire_lease_rates(&cursor, &plen, *lease_rates); + } + return cursor != NULL; +} +// SHA256STAMP:8651e9ad1638a311e744432336fe51e34abdb1779ef9bbc43a9656e954ba66fe diff --git a/openingd/dualopend_wiregen.h b/openingd/dualopend_wiregen.h index 0c1e9c6527ef..9a09df909f1c 100644 --- a/openingd/dualopend_wiregen.h +++ b/openingd/dualopend_wiregen.h @@ -72,6 +72,8 @@ enum dualopend_wire { /* master -> dualopend: do you have a memleak? */ WIRE_DUALOPEND_DEV_MEMLEAK = 7033, WIRE_DUALOPEND_DEV_MEMLEAK_REPLY = 7133, + /* dualopend -> master: this was a dry run */ + WIRE_DUALOPEND_DRY_RUN = 7026, }; const char *dualopend_wire_name(int e); @@ -153,8 +155,8 @@ bool fromwire_dualopend_fail(const tal_t *ctx, const void *p, wirestring **reaso /* WIRE: DUALOPEND_OPENER_INIT */ /* master->dualopend: hello */ -u8 *towire_dualopend_opener_init(const tal_t *ctx, const struct wally_psbt *psbt, struct amount_sat funding_amount, const u8 *local_shutdown_scriptpubkey, u32 feerate_per_kw, u32 feerate_per_kw_funding, u8 channel_flags, struct amount_sat requested_sats, u32 blockheight); -bool fromwire_dualopend_opener_init(const tal_t *ctx, const void *p, struct wally_psbt **psbt, struct amount_sat *funding_amount, u8 **local_shutdown_scriptpubkey, u32 *feerate_per_kw, u32 *feerate_per_kw_funding, u8 *channel_flags, struct amount_sat *requested_sats, u32 *blockheight); +u8 *towire_dualopend_opener_init(const tal_t *ctx, const struct wally_psbt *psbt, struct amount_sat funding_amount, const u8 *local_shutdown_scriptpubkey, u32 feerate_per_kw, u32 feerate_per_kw_funding, u8 channel_flags, struct amount_sat requested_sats, u32 blockheight, bool dry_run); +bool fromwire_dualopend_opener_init(const tal_t *ctx, const void *p, struct wally_psbt **psbt, struct amount_sat *funding_amount, u8 **local_shutdown_scriptpubkey, u32 *feerate_per_kw, u32 *feerate_per_kw_funding, u8 *channel_flags, struct amount_sat *requested_sats, u32 *blockheight, bool *dry_run); /* WIRE: DUALOPEND_FUNDING_SIGS */ /* dualopend->master received tx_sigs from peer */ @@ -215,6 +217,11 @@ bool fromwire_dualopend_dev_memleak(const void *p); u8 *towire_dualopend_dev_memleak_reply(const tal_t *ctx, bool leak); bool fromwire_dualopend_dev_memleak_reply(const void *p, bool *leak); +/* WIRE: DUALOPEND_DRY_RUN */ +/* dualopend -> master: this was a dry run */ +u8 *towire_dualopend_dry_run(const tal_t *ctx, const struct channel_id *channel_id, struct amount_sat our_funding, struct amount_sat their_funding, const struct lease_rates *lease_rates); +bool fromwire_dualopend_dry_run(const tal_t *ctx, const void *p, struct channel_id *channel_id, struct amount_sat *our_funding, struct amount_sat *their_funding, struct lease_rates **lease_rates); + #endif /* LIGHTNING_OPENINGD_DUALOPEND_WIREGEN_H */ -// SHA256STAMP:e450d9832b4f8b8303a2f887e451d3e3964d1dfeff5cbe41762232a02bcaf13f +// SHA256STAMP:8651e9ad1638a311e744432336fe51e34abdb1779ef9bbc43a9656e954ba66fe diff --git a/tests/test_opening.py b/tests/test_opening.py index 7758e7da1fdb..d8fa215c9ba4 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -1,6 +1,6 @@ from fixtures import * # noqa: F401,F403 from fixtures import TEST_NETWORK -from pyln.client import RpcError +from pyln.client import Millisatoshi, RpcError from utils import ( only_one, wait_for, sync_blockheight, first_channel_id ) @@ -15,6 +15,43 @@ def find_next_feerate(node, peer): return chan['next_feerate'] +@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') +@pytest.mark.openchannel('v2') +def test_queryrates(node_factory, bitcoind): + l1, l2 = node_factory.get_nodes(2) + + amount = 10 ** 6 + + l1.fundwallet(amount * 10) + l2.fundwallet(amount * 10) + + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + result = l1.rpc.queryrates(l2.info['id'], amount, amount * 10) + assert result['our_funding_msat'] == Millisatoshi(amount * 1000) + assert result['their_funding_msat'] == Millisatoshi(0) + assert 'weight_charge' not in result + + l2.rpc.call('funderupdate', {'policy': 'match', + 'policy_mod': 100, + 'per_channel_max': '1btc', + 'fuzz_percent': 0, + 'lease_fee_base_msat': '2sat', + 'funding_weight': 1000, + 'lease_fee_basis': 140, + 'channel_fee_max_base_msat': '3sat', + 'channel_fee_max_proportional_thousandths': 101}) + + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + result = l1.rpc.queryrates(l2.info['id'], amount, amount) + assert result['our_funding_msat'] == Millisatoshi(amount * 1000) + assert result['their_funding_msat'] == Millisatoshi(amount * 1000) + assert result['funding_weight'] == 1000 + assert result['lease_fee_base_msat'] == Millisatoshi(2000) + assert result['lease_fee_basis'] == 140 + assert result['channel_fee_max_base_msat'] == Millisatoshi(3000) + assert result['channel_fee_max_proportional_thousandths'] == 101 + + @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') @pytest.mark.developer("uses dev-disconnect") @pytest.mark.openchannel('v1') # Mixed v1 + v2, v2 manually turned on From 724e364a7d12cdfbb0ccbfc91b2bbec298ab7e24 Mon Sep 17 00:00:00 2001 From: niftynei Date: Mon, 14 Jun 2021 14:22:46 -0500 Subject: [PATCH 22/56] channel-lease: validate accepter's sig on lease terms --- common/lease_rates.c | 28 +++++++++ common/lease_rates.h | 10 ++++ common/test/run-lease_rates.c | 105 +++++++++++++++++++++++++++++++++ hsmd/Makefile | 1 + hsmd/libhsmd.c | 29 +++------ lightningd/dual_open_control.c | 70 ++++++++++++++++++++++ openingd/dualopend.c | 33 +++++++++-- openingd/dualopend_wire.csv | 12 ++++ openingd/dualopend_wiregen.c | 66 ++++++++++++++++++++- openingd/dualopend_wiregen.h | 15 ++++- 10 files changed, 343 insertions(+), 26 deletions(-) create mode 100644 common/test/run-lease_rates.c diff --git a/common/lease_rates.c b/common/lease_rates.c index cd70734a0428..eb8434737205 100644 --- a/common/lease_rates.c +++ b/common/lease_rates.c @@ -1,4 +1,6 @@ #include "config.h" +#include +#include #include #include #include @@ -17,6 +19,32 @@ bool lease_rates_empty(struct lease_rates *rates) && rates->lease_fee_basis == 0; } +void lease_rates_get_commitment(struct pubkey *pubkey, + u32 lease_expiry, + u32 chan_fee_msat, + u16 chan_fee_ppt, + struct sha256 *sha) +{ + struct sha256_ctx sctx = SHA256_INIT; + u8 der[PUBKEY_CMPR_LEN]; + /* BOLT- #2: + * - MUST set `signature` to the ECDSA signature of + * SHA256("option_will_fund" + * || `funding_pubkey` + * || `blockheight` + 4032 + * || `channel_fee_max_base_msat` + * || `channel_fee_max_proportional_thousandths`) + * using the node_id key. + */ + pubkey_to_der(der, pubkey); + sha256_update(&sctx, "option_will_fund", strlen("option_will_fund")); + sha256_update(&sctx, der, PUBKEY_CMPR_LEN); + sha256_be32(&sctx, lease_expiry); + sha256_be32(&sctx, chan_fee_msat); + sha256_be16(&sctx, chan_fee_ppt); + sha256_done(&sctx, sha); +} + bool lease_rates_set_chan_fee_base_msat(struct lease_rates *rates, struct amount_msat amt) { diff --git a/common/lease_rates.h b/common/lease_rates.h index 2c4a820025e2..cc7bc7aaf3d3 100644 --- a/common/lease_rates.h +++ b/common/lease_rates.h @@ -6,9 +6,19 @@ struct amount_msat; struct amount_sat; struct lease_rates; +struct pubkey; +struct sha256; + +#define LEASE_RATE_DURATION 4032 bool lease_rates_empty(struct lease_rates *rates); +void lease_rates_get_commitment(struct pubkey *pubkey, + u32 lease_expiry, + u32 chan_fee_msat, + u16 chan_fee_ppt, + struct sha256 *sha); + WARN_UNUSED_RESULT bool lease_rates_set_chan_fee_base_msat(struct lease_rates *rates, struct amount_msat amt); WARN_UNUSED_RESULT bool lease_rates_set_lease_fee_sat(struct lease_rates *rates, struct amount_sat amt); diff --git a/common/test/run-lease_rates.c b/common/test/run-lease_rates.c new file mode 100644 index 000000000000..45c2b502750e --- /dev/null +++ b/common/test/run-lease_rates.c @@ -0,0 +1,105 @@ +#include "../amount.c" +#include "../lease_rates.c" +#include +#include +#include +#include +#include +#include +#include + +/* AUTOGENERATED MOCKS START */ +/* Generated stub for fromwire */ +const u8 *fromwire(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, void *copy UNNEEDED, size_t n UNNEEDED) +{ fprintf(stderr, "fromwire called!\n"); abort(); } +/* Generated stub for fromwire_bool */ +bool fromwire_bool(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_bool called!\n"); abort(); } +/* Generated stub for fromwire_fail */ +void *fromwire_fail(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_fail called!\n"); abort(); } +/* Generated stub for fromwire_secp256k1_ecdsa_signature */ +void fromwire_secp256k1_ecdsa_signature(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, + secp256k1_ecdsa_signature *signature UNNEEDED) +{ fprintf(stderr, "fromwire_secp256k1_ecdsa_signature called!\n"); abort(); } +/* Generated stub for fromwire_sha256 */ +void fromwire_sha256(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct sha256 *sha256 UNNEEDED) +{ fprintf(stderr, "fromwire_sha256 called!\n"); abort(); } +/* Generated stub for fromwire_tal_arrn */ +u8 *fromwire_tal_arrn(const tal_t *ctx UNNEEDED, + const u8 **cursor UNNEEDED, size_t *max UNNEEDED, size_t num UNNEEDED) +{ fprintf(stderr, "fromwire_tal_arrn called!\n"); abort(); } +/* Generated stub for fromwire_u16 */ +u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_u16 called!\n"); abort(); } +/* Generated stub for fromwire_u32 */ +u32 fromwire_u32(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_u32 called!\n"); abort(); } +/* Generated stub for fromwire_u64 */ +u64 fromwire_u64(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_u64 called!\n"); abort(); } +/* Generated stub for fromwire_u8 */ +u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_u8 called!\n"); abort(); } +/* Generated stub for fromwire_u8_array */ +void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED) +{ fprintf(stderr, "fromwire_u8_array called!\n"); abort(); } +/* Generated stub for towire */ +void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED) +{ fprintf(stderr, "towire called!\n"); abort(); } +/* Generated stub for towire_bool */ +void towire_bool(u8 **pptr UNNEEDED, bool v UNNEEDED) +{ fprintf(stderr, "towire_bool called!\n"); abort(); } +/* Generated stub for towire_secp256k1_ecdsa_signature */ +void towire_secp256k1_ecdsa_signature(u8 **pptr UNNEEDED, + const secp256k1_ecdsa_signature *signature UNNEEDED) +{ fprintf(stderr, "towire_secp256k1_ecdsa_signature called!\n"); abort(); } +/* Generated stub for towire_sha256 */ +void towire_sha256(u8 **pptr UNNEEDED, const struct sha256 *sha256 UNNEEDED) +{ fprintf(stderr, "towire_sha256 called!\n"); abort(); } +/* Generated stub for towire_u16 */ +void towire_u16(u8 **pptr UNNEEDED, u16 v UNNEEDED) +{ fprintf(stderr, "towire_u16 called!\n"); abort(); } +/* Generated stub for towire_u32 */ +void towire_u32(u8 **pptr UNNEEDED, u32 v UNNEEDED) +{ fprintf(stderr, "towire_u32 called!\n"); abort(); } +/* Generated stub for towire_u64 */ +void towire_u64(u8 **pptr UNNEEDED, u64 v UNNEEDED) +{ fprintf(stderr, "towire_u64 called!\n"); abort(); } +/* Generated stub for towire_u8 */ +void towire_u8(u8 **pptr UNNEEDED, u8 v UNNEEDED) +{ fprintf(stderr, "towire_u8 called!\n"); abort(); } +/* Generated stub for towire_u8_array */ +void towire_u8_array(u8 **pptr UNNEEDED, const u8 *arr UNNEEDED, size_t num UNNEEDED) +{ fprintf(stderr, "towire_u8_array called!\n"); abort(); } +/* AUTOGENERATED MOCKS END */ + +static void check_lease_rate_commitment_hash(void) +{ + struct pubkey p; + struct sha256 sha; + u8 *expected; + assert(pubkey_from_hexstr("032cf15d1ad9c4a08d26eab1918f732d8ef8fdc6abb9640bf3db174372c491304e", strlen("032cf15d1ad9c4a08d26eab1918f732d8ef8fdc6abb9640bf3db174372c491304e"), &p)); + lease_rates_get_commitment(&p, 0, 0, 0, &sha); + + expected = tal_hexdata(tmpctx, "adc2973c151fecf212019dc3228a6765277cec6ab958959923839238a01cc1ce", strlen("adc2973c151fecf212019dc3228a6765277cec6ab958959923839238a01cc1ce")); + + assert(memeq(expected, tal_bytelen(expected), + &sha.u.u8, sizeof(sha.u.u8))); + + lease_rates_get_commitment(&p, 255, 100, 50, &sha); + expected = tal_hexdata(tmpctx, "d363b338db30a4abd184e576773befb6a05ba61cec4169998ccbf546a720e421", strlen("d363b338db30a4abd184e576773befb6a05ba61cec4169998ccbf546a720e421")); + + assert(memeq(expected, tal_bytelen(expected), + &sha.u.u8, sizeof(sha.u.u8))); + +} + +int main(int argc, char *argv[]) +{ + common_setup(argv[0]); + + check_lease_rate_commitment_hash(); + + common_shutdown(); +} diff --git a/hsmd/Makefile b/hsmd/Makefile index 6e18705243ea..afd120d649e6 100644 --- a/hsmd/Makefile +++ b/hsmd/Makefile @@ -31,6 +31,7 @@ HSMD_COMMON_OBJS := \ common/hash_u5.o \ common/hsm_encryption.o \ common/key_derive.o \ + common/lease_rates.o \ common/memleak.o \ common/msg_queue.o \ common/node_id.o \ diff --git a/hsmd/libhsmd.c b/hsmd/libhsmd.c index 0f2cacdcfb04..944982f1da38 100644 --- a/hsmd/libhsmd.c +++ b/hsmd/libhsmd.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -477,35 +478,23 @@ static u8 *handle_sign_option_will_fund_offer(struct hsmd_client *c, const u8 *msg_in) { struct pubkey funding_pubkey; - u32 blockheight, channel_fee_base_max_msat; - u16 channel_fee_proportional_basis_max; - struct sha256_ctx sctx = SHA256_INIT; + u32 lease_expiry, channel_fee_base_max_msat; + u16 channel_fee_max_ppt; struct sha256 sha; secp256k1_ecdsa_signature sig; struct privkey node_pkey; if (!fromwire_hsmd_sign_option_will_fund_offer(msg_in, &funding_pubkey, - &blockheight, + &lease_expiry, &channel_fee_base_max_msat, - &channel_fee_proportional_basis_max)) + &channel_fee_max_ppt)) return hsmd_status_malformed_request(c, msg_in); - /* BOLT- #2: - * - MUST set `signature` to the ECDSA signature of - * SHA256("option_will_fund" || `funding_pubkey`|| `blockheight` || - * `channel_fee_base_max_msat` || - * `channel_fee_proportional_basis_max`) - */ - sha256_update(&sctx, "option_will_fund", - strlen("option_will_fund")); - sha256_update(&sctx, &funding_pubkey, sizeof(funding_pubkey)); - sha256_update(&sctx, &blockheight, sizeof(blockheight)); - sha256_update(&sctx, &channel_fee_base_max_msat, - sizeof(channel_fee_base_max_msat)); - sha256_update(&sctx, &channel_fee_base_max_msat, - sizeof(channel_fee_base_max_msat)); - sha256_done(&sctx, &sha); + lease_rates_get_commitment(&funding_pubkey, lease_expiry, + channel_fee_base_max_msat, + channel_fee_max_ppt, + &sha); node_key(&node_pkey, NULL); diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index b26b41b428ec..464ef2a5336c 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -1913,6 +1913,72 @@ static void handle_peer_tx_sigs_msg(struct subd *dualopend, inflight->funding_psbt); } +static bool verify_option_will_fund_signature(struct peer *peer, + struct pubkey *funding_pubkey, + u32 lease_expiry, + u32 chan_fee_msat, + u16 chan_fee_ppt, + const secp256k1_ecdsa_signature *sig) + +{ + struct pubkey their_pubkey; + struct sha256 sha; + int ret; + + lease_rates_get_commitment(funding_pubkey, lease_expiry, + chan_fee_msat, chan_fee_ppt, + &sha); + + if (!pubkey_from_node_id(&their_pubkey, &peer->id)) { + log_broken(peer->ld->log, + "Unable to extract pubkey from peer's node id %s", + type_to_string(tmpctx, struct node_id, &peer->id)); + return false; + } + + ret = secp256k1_ecdsa_verify(secp256k1_ctx, sig, sha.u.u8, + &their_pubkey.pubkey); + return ret == 1; +} + +static void handle_validate_lease(struct subd *dualopend, + const u8 *msg) +{ + const secp256k1_ecdsa_signature sig; + u16 chan_fee_max_ppt; + u32 chan_fee_max_base_msat, lease_expiry; + struct pubkey their_pubkey; + struct channel *chan; + char *err_msg; + + if (!fromwire_dualopend_validate_lease(msg, + cast_const(secp256k1_ecdsa_signature *, &sig), + &lease_expiry, + &chan_fee_max_base_msat, + &chan_fee_max_ppt, + &their_pubkey)) { + channel_internal_error(dualopend->channel, + "Bad DUALOPEND_VALIDATE_LEASE: %s", + tal_hex(tmpctx, msg)); + return; + } + + assert(dualopend->channel); + chan = dualopend->channel; + + if (!verify_option_will_fund_signature(chan->peer, &their_pubkey, + lease_expiry, + chan_fee_max_base_msat, + chan_fee_max_ppt, + &sig)) + err_msg = "Unable to verify sig"; + else + err_msg = NULL; + + subd_send_msg(dualopend, + take(towire_dualopend_validate_lease_reply(NULL, err_msg))); +} + static void handle_validate_rbf(struct subd *dualopend, const u8 *msg) { @@ -2910,6 +2976,9 @@ static unsigned int dual_opend_msg(struct subd *dualopend, case WIRE_DUALOPEND_RBF_VALIDATE: handle_validate_rbf(dualopend, msg); return 0; + case WIRE_DUALOPEND_VALIDATE_LEASE: + handle_validate_lease(dualopend, msg); + return 0; case WIRE_DUALOPEND_FUNDING_SIGS: handle_peer_tx_sigs_msg(dualopend, msg); return 0; @@ -2948,6 +3017,7 @@ static unsigned int dual_opend_msg(struct subd *dualopend, case WIRE_DUALOPEND_GOT_OFFER_REPLY: case WIRE_DUALOPEND_GOT_RBF_OFFER_REPLY: case WIRE_DUALOPEND_RBF_VALID: + case WIRE_DUALOPEND_VALIDATE_LEASE_REPLY: case WIRE_DUALOPEND_FAIL: case WIRE_DUALOPEND_PSBT_UPDATED: case WIRE_DUALOPEND_SEND_TX_SIGS: diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 1ccbbc01227a..47992af76ac5 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -2160,7 +2161,7 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) if (open_tlv->request_funds && tx_state->rates) accept_tlv_add_offer(a_tlv, tx_state->rates, state->our_funding_pubkey, - lease_blockheight_start); + lease_blockheight_start + LEASE_RATE_DURATION); msg = towire_accept_channel2(tmpctx, &state->channel_id, tx_state->accepter_funding, @@ -2468,7 +2469,7 @@ static void opener_start(struct state *state, u8 *msg) struct channel_id cid; char *err_reason; struct amount_sat total, requested_sats; - u32 current_blockheight; + u32 current_blockheight, lease_expiry; bool dry_run; struct tx_state *tx_state = state->tx_state; @@ -2622,8 +2623,30 @@ static void opener_start(struct state *state, u8 *msg) /* FIXME: BOLT QUOTE */ if (open_tlv->request_funds && a_tlv->will_fund) { - /* OK! lease mode activated */ - } + char *err_msg; + struct lease_rates *rates = &a_tlv->will_fund->lease_rates; + + lease_expiry = current_blockheight + LEASE_RATE_DURATION; + + msg = towire_dualopend_validate_lease(NULL, + &a_tlv->will_fund->signature, + lease_expiry, + rates->channel_fee_max_base_msat, + rates->channel_fee_max_proportional_thousandths, + &state->their_funding_pubkey); + + + wire_sync_write(REQ_FD, take(msg)); + msg = wire_sync_read(tmpctx, REQ_FD); + + if (!fromwire_dualopend_validate_lease_reply(tmpctx, msg, + &err_msg)) + master_badmsg(WIRE_DUALOPEND_VALIDATE_LEASE_REPLY, msg); + + if (err_msg) + open_err_warn(state, "%s", err_msg); + } else + lease_expiry = 0; /* Check that total funding doesn't overflow */ if (!amount_sat_add(&total, tx_state->opener_funding, @@ -3404,6 +3427,7 @@ static u8 *handle_master_in(struct state *state) case WIRE_DUALOPEND_GOT_OFFER_REPLY: case WIRE_DUALOPEND_GOT_RBF_OFFER_REPLY: case WIRE_DUALOPEND_RBF_VALID: + case WIRE_DUALOPEND_VALIDATE_LEASE_REPLY: /* Messages we send */ case WIRE_DUALOPEND_GOT_OFFER: @@ -3419,6 +3443,7 @@ static u8 *handle_master_in(struct state *state) case WIRE_DUALOPEND_SHUTDOWN_COMPLETE: case WIRE_DUALOPEND_FAIL_FALLEN_BEHIND: case WIRE_DUALOPEND_DRY_RUN: + case WIRE_DUALOPEND_VALIDATE_LEASE: break; } diff --git a/openingd/dualopend_wire.csv b/openingd/dualopend_wire.csv index 554a8162878c..558abc98198e 100644 --- a/openingd/dualopend_wire.csv +++ b/openingd/dualopend_wire.csv @@ -9,6 +9,7 @@ #include #include #include +#include #include msgtype,dualopend_init,7000 @@ -221,3 +222,14 @@ msgdata,dualopend_dry_run,channel_id,channel_id, msgdata,dualopend_dry_run,our_funding,amount_sat, msgdata,dualopend_dry_run,their_funding,amount_sat, msgdata,dualopend_dry_run,lease_rates,?lease_rates, + +# dualopend -> master: validate liqudity offer sig +msgtype,dualopend_validate_lease,7027 +msgdata,dualopend_validate_lease,sig,secp256k1_ecdsa_signature, +msgdata,dualopend_validate_lease,lease_expiry,u32, +msgdata,dualopend_validate_lease,chan_fee_max_base_msat,u32, +msgdata,dualopend_validate_lease,chan_fee_max_ppt,u16, +msgdata,dualopend_validate_lease,their_pubkey,pubkey, + +msgtype,dualopend_validate_lease_reply,7127 +msgdata,dualopend_validate_lease_reply,err_msg,?wirestring, diff --git a/openingd/dualopend_wiregen.c b/openingd/dualopend_wiregen.c index 0ab4110fee90..2fa679a99917 100644 --- a/openingd/dualopend_wiregen.c +++ b/openingd/dualopend_wiregen.c @@ -47,6 +47,8 @@ const char *dualopend_wire_name(int e) case WIRE_DUALOPEND_DEV_MEMLEAK: return "WIRE_DUALOPEND_DEV_MEMLEAK"; case WIRE_DUALOPEND_DEV_MEMLEAK_REPLY: return "WIRE_DUALOPEND_DEV_MEMLEAK_REPLY"; case WIRE_DUALOPEND_DRY_RUN: return "WIRE_DUALOPEND_DRY_RUN"; + case WIRE_DUALOPEND_VALIDATE_LEASE: return "WIRE_DUALOPEND_VALIDATE_LEASE"; + case WIRE_DUALOPEND_VALIDATE_LEASE_REPLY: return "WIRE_DUALOPEND_VALIDATE_LEASE_REPLY"; } snprintf(invalidbuf, sizeof(invalidbuf), "INVALID %i", e); @@ -83,6 +85,8 @@ bool dualopend_wire_is_defined(u16 type) case WIRE_DUALOPEND_DEV_MEMLEAK:; case WIRE_DUALOPEND_DEV_MEMLEAK_REPLY:; case WIRE_DUALOPEND_DRY_RUN:; + case WIRE_DUALOPEND_VALIDATE_LEASE:; + case WIRE_DUALOPEND_VALIDATE_LEASE_REPLY:; return true; } return false; @@ -974,4 +978,64 @@ bool fromwire_dualopend_dry_run(const tal_t *ctx, const void *p, struct channel_ } return cursor != NULL; } -// SHA256STAMP:8651e9ad1638a311e744432336fe51e34abdb1779ef9bbc43a9656e954ba66fe + +/* WIRE: DUALOPEND_VALIDATE_LEASE */ +/* dualopend -> master: validate liqudity offer sig */ +u8 *towire_dualopend_validate_lease(const tal_t *ctx, const secp256k1_ecdsa_signature *sig, u32 lease_expiry, u32 chan_fee_max_base_msat, u16 chan_fee_max_ppt, const struct pubkey *their_pubkey) +{ + u8 *p = tal_arr(ctx, u8, 0); + + towire_u16(&p, WIRE_DUALOPEND_VALIDATE_LEASE); + towire_secp256k1_ecdsa_signature(&p, sig); + towire_u32(&p, lease_expiry); + towire_u32(&p, chan_fee_max_base_msat); + towire_u16(&p, chan_fee_max_ppt); + towire_pubkey(&p, their_pubkey); + + return memcheck(p, tal_count(p)); +} +bool fromwire_dualopend_validate_lease(const void *p, secp256k1_ecdsa_signature *sig, u32 *lease_expiry, u32 *chan_fee_max_base_msat, u16 *chan_fee_max_ppt, struct pubkey *their_pubkey) +{ + const u8 *cursor = p; + size_t plen = tal_count(p); + + if (fromwire_u16(&cursor, &plen) != WIRE_DUALOPEND_VALIDATE_LEASE) + return false; + fromwire_secp256k1_ecdsa_signature(&cursor, &plen, sig); + *lease_expiry = fromwire_u32(&cursor, &plen); + *chan_fee_max_base_msat = fromwire_u32(&cursor, &plen); + *chan_fee_max_ppt = fromwire_u16(&cursor, &plen); + fromwire_pubkey(&cursor, &plen, their_pubkey); + return cursor != NULL; +} + +/* WIRE: DUALOPEND_VALIDATE_LEASE_REPLY */ +u8 *towire_dualopend_validate_lease_reply(const tal_t *ctx, const wirestring *err_msg) +{ + u8 *p = tal_arr(ctx, u8, 0); + + towire_u16(&p, WIRE_DUALOPEND_VALIDATE_LEASE_REPLY); + if (!err_msg) + towire_bool(&p, false); + else { + towire_bool(&p, true); + towire_wirestring(&p, err_msg); + } + + return memcheck(p, tal_count(p)); +} +bool fromwire_dualopend_validate_lease_reply(const tal_t *ctx, const void *p, wirestring **err_msg) +{ + const u8 *cursor = p; + size_t plen = tal_count(p); + + if (fromwire_u16(&cursor, &plen) != WIRE_DUALOPEND_VALIDATE_LEASE_REPLY) + return false; + if (!fromwire_bool(&cursor, &plen)) + *err_msg = NULL; + else { + *err_msg = fromwire_wirestring(ctx, &cursor, &plen); + } + return cursor != NULL; +} +// SHA256STAMP:ef969c3a15ae09102caa6f57f676a295e86f3fc1c01347c3fb9c6004bb6c7109 diff --git a/openingd/dualopend_wiregen.h b/openingd/dualopend_wiregen.h index 9a09df909f1c..82ea606f1591 100644 --- a/openingd/dualopend_wiregen.h +++ b/openingd/dualopend_wiregen.h @@ -18,6 +18,7 @@ #include #include #include +#include #include enum dualopend_wire { @@ -74,6 +75,9 @@ enum dualopend_wire { WIRE_DUALOPEND_DEV_MEMLEAK_REPLY = 7133, /* dualopend -> master: this was a dry run */ WIRE_DUALOPEND_DRY_RUN = 7026, + /* dualopend -> master: validate liqudity offer sig */ + WIRE_DUALOPEND_VALIDATE_LEASE = 7027, + WIRE_DUALOPEND_VALIDATE_LEASE_REPLY = 7127, }; const char *dualopend_wire_name(int e); @@ -222,6 +226,15 @@ bool fromwire_dualopend_dev_memleak_reply(const void *p, bool *leak); u8 *towire_dualopend_dry_run(const tal_t *ctx, const struct channel_id *channel_id, struct amount_sat our_funding, struct amount_sat their_funding, const struct lease_rates *lease_rates); bool fromwire_dualopend_dry_run(const tal_t *ctx, const void *p, struct channel_id *channel_id, struct amount_sat *our_funding, struct amount_sat *their_funding, struct lease_rates **lease_rates); +/* WIRE: DUALOPEND_VALIDATE_LEASE */ +/* dualopend -> master: validate liqudity offer sig */ +u8 *towire_dualopend_validate_lease(const tal_t *ctx, const secp256k1_ecdsa_signature *sig, u32 lease_expiry, u32 chan_fee_max_base_msat, u16 chan_fee_max_ppt, const struct pubkey *their_pubkey); +bool fromwire_dualopend_validate_lease(const void *p, secp256k1_ecdsa_signature *sig, u32 *lease_expiry, u32 *chan_fee_max_base_msat, u16 *chan_fee_max_ppt, struct pubkey *their_pubkey); + +/* WIRE: DUALOPEND_VALIDATE_LEASE_REPLY */ +u8 *towire_dualopend_validate_lease_reply(const tal_t *ctx, const wirestring *err_msg); +bool fromwire_dualopend_validate_lease_reply(const tal_t *ctx, const void *p, wirestring **err_msg); + #endif /* LIGHTNING_OPENINGD_DUALOPEND_WIREGEN_H */ -// SHA256STAMP:8651e9ad1638a311e744432336fe51e34abdb1779ef9bbc43a9656e954ba66fe +// SHA256STAMP:ef969c3a15ae09102caa6f57f676a295e86f3fc1c01347c3fb9c6004bb6c7109 From bba10e1f8dcc291b79a3a9a672b890806d237592 Mon Sep 17 00:00:00 2001 From: niftynei Date: Mon, 14 Jun 2021 17:49:57 -0500 Subject: [PATCH 23/56] lease-rates: calculate the fee owed to peer for the funds lease --- common/lease_rates.c | 35 +++++++++++++++++++++++++ common/lease_rates.h | 6 +++++ common/test/run-lease_rates.c | 31 ++++++++++++++++++++++ openingd/Makefile | 1 + openingd/dualopend.c | 49 +++++++++++++++++++++++++++++++---- 5 files changed, 117 insertions(+), 5 deletions(-) diff --git a/common/lease_rates.c b/common/lease_rates.c index eb8434737205..c58939c91f56 100644 --- a/common/lease_rates.c +++ b/common/lease_rates.c @@ -45,6 +45,41 @@ void lease_rates_get_commitment(struct pubkey *pubkey, sha256_done(&sctx, sha); } +bool lease_rates_calc_fee(struct lease_rates *rates, + struct amount_sat accept_funding_sats, + struct amount_sat requested_sats, + u32 onchain_feerate, + struct amount_sat *fee) +{ + struct amount_sat lease_fee, basis_sat, tx_fee; + /* BOLT- #2: + * The lease fee is calculated as: + * `lease_fee_base_sat` + + * min(`accept_channel2`.`funding_satoshis`, `open_channel2`.`requested_sats`) * `lease_fee_basis` / 10_000 + + * `funding_weight` * `funding_feerate_perkw` / 1000 + */ + + lease_fee = amount_sat(rates->lease_fee_base_sat); + basis_sat = amount_sat_less(accept_funding_sats, requested_sats) + ? accept_funding_sats : requested_sats; + + if (!amount_sat_scale(&basis_sat, basis_sat, + rates->lease_fee_basis)) + return false; + + basis_sat = amount_sat_div(basis_sat, 10000); + + if (!amount_sat_add(&lease_fee, lease_fee, basis_sat)) + return false; + + tx_fee = amount_tx_fee(onchain_feerate, rates->funding_weight); + if (!amount_sat_add(&lease_fee, lease_fee, tx_fee)) + return false; + + *fee = lease_fee; + return true; +} + bool lease_rates_set_chan_fee_base_msat(struct lease_rates *rates, struct amount_msat amt) { diff --git a/common/lease_rates.h b/common/lease_rates.h index cc7bc7aaf3d3..e72edb92d598 100644 --- a/common/lease_rates.h +++ b/common/lease_rates.h @@ -19,6 +19,12 @@ void lease_rates_get_commitment(struct pubkey *pubkey, u16 chan_fee_ppt, struct sha256 *sha); +bool lease_rates_calc_fee(struct lease_rates *rates, + struct amount_sat accept_funding_sats, + struct amount_sat requested_sats, + u32 onchain_feerate, + struct amount_sat *fee); + WARN_UNUSED_RESULT bool lease_rates_set_chan_fee_base_msat(struct lease_rates *rates, struct amount_msat amt); WARN_UNUSED_RESULT bool lease_rates_set_lease_fee_sat(struct lease_rates *rates, struct amount_sat amt); diff --git a/common/test/run-lease_rates.c b/common/test/run-lease_rates.c index 45c2b502750e..8ba88af8e1b4 100644 --- a/common/test/run-lease_rates.c +++ b/common/test/run-lease_rates.c @@ -95,11 +95,42 @@ static void check_lease_rate_commitment_hash(void) } +static void check_lease_rate_fees(void) +{ + /* BOLT- #2: + * E.g. + * An node requests 1_000_000sats at a feerate of 2500perkw. They + * are contributing 500_000sats. Their weight contribution to the + * funding transaction will be 720. + * + * The accepter adds 1,100,000sats and charges a base funding fee of + * 233sats with a lease fee basis of 22. Their funding weight is 444. + * The lease fee is as follows: + * 233 + min(1_000_000,1_100_000) * 22 / 10_000 + 444 * 2500 / 1000 + * The total lease fee for this open is 3543sats. + */ + struct amount_sat request_sats = amount_sat(1000000); + struct amount_sat accepter_contrib = amount_sat(1100000); + struct amount_sat fee; + struct lease_rates rates; + u32 feerate = 2500; + + rates.lease_fee_basis = 22; + rates.lease_fee_base_sat = 233; + rates.funding_weight = 444; + + assert(lease_rates_calc_fee(&rates, accepter_contrib, + request_sats, feerate, + &fee)); + assert(amount_sat_eq(fee, amount_sat(3543))); +} + int main(int argc, char *argv[]) { common_setup(argv[0]); check_lease_rate_commitment_hash(); + check_lease_rate_fees(); common_shutdown(); } diff --git a/openingd/Makefile b/openingd/Makefile index 425a7021a033..98b176ec07b5 100644 --- a/openingd/Makefile +++ b/openingd/Makefile @@ -57,6 +57,7 @@ OPENINGD_COMMON_OBJS := \ common/initial_commit_tx.o \ common/key_derive.o \ common/keyset.o \ + common/lease_rates.o \ common/memleak.o \ common/msg_queue.o \ common/node_id.o \ diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 47992af76ac5..a55dc860d7b5 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -193,6 +193,9 @@ struct state { /* State of inflight funding transaction attempt */ struct tx_state *tx_state; + + /* If delay til the channel funds lease expires */ + u32 lease_expiry; }; /* psbt_changeset_get_next - Get next message to send @@ -2469,7 +2472,7 @@ static void opener_start(struct state *state, u8 *msg) struct channel_id cid; char *err_reason; struct amount_sat total, requested_sats; - u32 current_blockheight, lease_expiry; + u32 current_blockheight; bool dry_run; struct tx_state *tx_state = state->tx_state; @@ -2621,16 +2624,21 @@ static void opener_start(struct state *state, u8 *msg) open_err_warn(state, "%s", "Abort requested"); } - /* FIXME: BOLT QUOTE */ + /* BOLT- #2: + * The accepting node: ... + * - if they decide to accept the offer: + * - MUST include a `will_fund` tlv + */ if (open_tlv->request_funds && a_tlv->will_fund) { char *err_msg; struct lease_rates *rates = &a_tlv->will_fund->lease_rates; + struct amount_sat lease_fee; - lease_expiry = current_blockheight + LEASE_RATE_DURATION; + state->lease_expiry = current_blockheight + LEASE_RATE_DURATION; msg = towire_dualopend_validate_lease(NULL, &a_tlv->will_fund->signature, - lease_expiry, + state->lease_expiry, rates->channel_fee_max_base_msat, rates->channel_fee_max_proportional_thousandths, &state->their_funding_pubkey); @@ -2645,8 +2653,39 @@ static void opener_start(struct state *state, u8 *msg) if (err_msg) open_err_warn(state, "%s", err_msg); + + /* BOLT- #2: + * The lease fee is added to the accepter's balance + * in a channel, in addition to the `funding_satoshi` + * that they are contributing. The channel initiator + * must contribute enough funds to cover + * `open_channel2`.`funding_satoshis`, the lease fee, + * and their tx weight * `funding_feerate_perkw` / 1000. + */ + if (!lease_rates_calc_fee(rates, tx_state->accepter_funding, + requested_sats, + state->feerate_per_kw_funding, + &lease_fee)) + negotiation_failed(state, + "Unable to calculate lease fee"); + + /* Add it to the accepter's total */ + if (!amount_sat_add(&tx_state->accepter_funding, + tx_state->accepter_funding, lease_fee)) { + + negotiation_failed(state, + "Unable to add accepter's funding" + " and channel lease fee (%s + %s)", + type_to_string(tmpctx, + struct amount_sat, + &tx_state->accepter_funding), + type_to_string(tmpctx, + struct amount_sat, + &lease_fee)); + return; + } } else - lease_expiry = 0; + state->lease_expiry = 0; /* Check that total funding doesn't overflow */ if (!amount_sat_add(&total, tx_state->opener_funding, From 6b3299bdb699e0547f437195ff30a1a45b02ea18 Mon Sep 17 00:00:00 2001 From: niftynei Date: Mon, 14 Jun 2021 17:56:50 -0500 Subject: [PATCH 24/56] lease-rates: add to accepter's side on accepter pathway --- openingd/dualopend.c | 53 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/openingd/dualopend.c b/openingd/dualopend.c index a55dc860d7b5..3ae0328f5131 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -123,6 +123,9 @@ struct tx_state { /* Rates that we're using for this open... */ struct lease_rates *rates; + + /* If delay til the channel funds lease expires */ + u32 lease_expiry; }; static struct tx_state *new_tx_state(const tal_t *ctx) @@ -193,9 +196,6 @@ struct state { /* State of inflight funding transaction attempt */ struct tx_state *tx_state; - - /* If delay til the channel funds lease expires */ - u32 lease_expiry; }; /* psbt_changeset_get_next - Get next message to send @@ -2190,6 +2190,47 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) sync_crypto_write(state->pps, msg); peer_billboard(false, "channel open: accept sent, waiting for reply"); + /* Add our fee to our amount now */ + if (tx_state->rates) { + struct amount_sat lease_fee; + + tx_state->lease_expiry + = lease_blockheight_start + LEASE_RATE_DURATION; + + /* BOLT- #2: + * The lease fee is added to the accepter's balance + * in a channel, in addition to the `funding_satoshi` + * that they are contributing. The channel initiator + * must contribute enough funds to cover + * `open_channel2`.`funding_satoshis`, the lease fee, + * and their tx weight * `funding_feerate_perkw` / 1000. + */ + if (!lease_rates_calc_fee(tx_state->rates, + tx_state->accepter_funding, + requested_amt, + state->feerate_per_kw_funding, + &lease_fee)) + negotiation_failed(state, + "Unable to calculate lease fee"); + + /* Add it to the accepter's total */ + if (!amount_sat_add(&tx_state->accepter_funding, + tx_state->accepter_funding, lease_fee)) { + + negotiation_failed(state, + "Unable to add accepter's funding" + " and channel lease fee (%s + %s)", + type_to_string(tmpctx, + struct amount_sat, + &tx_state->accepter_funding), + type_to_string(tmpctx, + struct amount_sat, + &lease_fee)); + return; + } + } else + tx_state->lease_expiry = 0; + /* This is unused in this flow. We re-use * the wire method between accepter + opener, so we set it * to an invalid number, 1 (initiator sets; valid is even) */ @@ -2634,11 +2675,11 @@ static void opener_start(struct state *state, u8 *msg) struct lease_rates *rates = &a_tlv->will_fund->lease_rates; struct amount_sat lease_fee; - state->lease_expiry = current_blockheight + LEASE_RATE_DURATION; + tx_state->lease_expiry = current_blockheight + LEASE_RATE_DURATION; msg = towire_dualopend_validate_lease(NULL, &a_tlv->will_fund->signature, - state->lease_expiry, + tx_state->lease_expiry, rates->channel_fee_max_base_msat, rates->channel_fee_max_proportional_thousandths, &state->their_funding_pubkey); @@ -2685,7 +2726,7 @@ static void opener_start(struct state *state, u8 *msg) return; } } else - state->lease_expiry = 0; + tx_state->lease_expiry = 0; /* Check that total funding doesn't overflow */ if (!amount_sat_add(&total, tx_state->opener_funding, From 8ac285372d0b414d614158261626c68634bfdb0e Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 15 Jun 2021 15:08:44 -0500 Subject: [PATCH 25/56] script: add csv_lock to scripts --- bitcoin/script.c | 15 +++++++++++++-- bitcoin/script.h | 3 ++- channeld/commit_tx.c | 2 +- common/initial_commit_tx.c | 2 +- hsmd/libhsmd.c | 2 +- onchaind/onchaind.c | 16 ++++++++++------ 6 files changed, 28 insertions(+), 12 deletions(-) diff --git a/bitcoin/script.c b/bitcoin/script.c index 2ca0e1da3b5b..cbf45858b095 100644 --- a/bitcoin/script.c +++ b/bitcoin/script.c @@ -327,13 +327,24 @@ u8 *scriptpubkey_witness_raw(const tal_t *ctx, u8 version, * block csv lock. * OP_CHECKSIGVERIFY 1 OP_CHECKSEQUENCEVERIFY */ +/* BOLT- #3 + * ##### Leased channel (`option_will_fund`) + * + * If a `lease` applies to the channel, the `to_remote` output + * of the `initiator` ensures the `leasor` funds are not + * spendable until the lease expires. + * + * OP_CHECKSIGVERIFY MAX(1, lease_end - blockheight) OP_CHECKSEQUENCEVERIFY + */ + u8 *anchor_to_remote_redeem(const tal_t *ctx, - const struct pubkey *remote_key) + const struct pubkey *remote_key, + u32 csv_lock) { u8 *script = tal_arr(ctx, u8, 0); add_push_key(&script, remote_key); add_op(&script, OP_CHECKSIGVERIFY); - add_number(&script, 1); + add_number(&script, csv_lock); add_op(&script, OP_CHECKSEQUENCEVERIFY); assert(is_anchor_witness_script(script, tal_bytelen(script))); diff --git a/bitcoin/script.h b/bitcoin/script.h index 939ecdc9c332..351bbcda0e92 100644 --- a/bitcoin/script.h +++ b/bitcoin/script.h @@ -69,7 +69,8 @@ u8 *scriptpubkey_witness_raw(const tal_t *ctx, u8 version, /* To-remotekey with csv 1 delay. */ u8 *anchor_to_remote_redeem(const tal_t *ctx, - const struct pubkey *remote_key); + const struct pubkey *remote_key, + u32 csv_lock); /* Create a witness which spends the 2of2. */ u8 **bitcoin_witness_2of2(const tal_t *ctx, diff --git a/channeld/commit_tx.c b/channeld/commit_tx.c index 1b4fd94cfc6e..77ad07c0b3b6 100644 --- a/channeld/commit_tx.c +++ b/channeld/commit_tx.c @@ -276,7 +276,7 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx, */ if (option_anchor_outputs) { scriptpubkey = scriptpubkey_p2wsh(tmpctx, - anchor_to_remote_redeem(tmpctx, &keyset->other_payment_key)); + anchor_to_remote_redeem(tmpctx, &keyset->other_payment_key, 1)); } else { scriptpubkey = scriptpubkey_p2wpkh(tmpctx, &keyset->other_payment_key); diff --git a/common/initial_commit_tx.c b/common/initial_commit_tx.c index c18201b4261b..792b32be4130 100644 --- a/common/initial_commit_tx.c +++ b/common/initial_commit_tx.c @@ -242,7 +242,7 @@ struct bitcoin_tx *initial_commit_tx(const tal_t *ctx, amount = amount_msat_to_sat_round_down(other_pay); if (option_anchor_outputs) { scriptpubkey = scriptpubkey_p2wsh(tmpctx, - anchor_to_remote_redeem(tmpctx, &keyset->other_payment_key)); + anchor_to_remote_redeem(tmpctx, &keyset->other_payment_key, 1)); } else { scriptpubkey = scriptpubkey_p2wpkh(tmpctx, &keyset->other_payment_key); diff --git a/hsmd/libhsmd.c b/hsmd/libhsmd.c index 944982f1da38..5d026fbe507c 100644 --- a/hsmd/libhsmd.c +++ b/hsmd/libhsmd.c @@ -388,7 +388,7 @@ static void sign_our_inputs(struct utxo **utxos, struct wally_psbt *psbt) /* It's actually a P2WSH in this case. */ if (utxo->close_info && utxo->close_info->option_anchor_outputs) { - const u8 *wscript = anchor_to_remote_redeem(tmpctx, &pubkey); + const u8 *wscript = anchor_to_remote_redeem(tmpctx, &pubkey, 1); psbt_input_set_witscript(psbt, j, wscript); psbt_input_set_wit_utxo(psbt, j, scriptpubkey_p2wsh(psbt, wscript), diff --git a/onchaind/onchaind.c b/onchaind/onchaind.c index 22b6413ce780..2cc8f01f3e30 100644 --- a/onchaind/onchaind.c +++ b/onchaind/onchaind.c @@ -2557,7 +2557,8 @@ static void get_anchor_scriptpubkeys(const tal_t *ctx, u8 **anchor) } static u8 *scriptpubkey_to_remote(const tal_t *ctx, - const struct pubkey *remotekey) + const struct pubkey *remotekey, + u32 csv_lock) { /* BOLT #3: * @@ -2574,7 +2575,8 @@ static u8 *scriptpubkey_to_remote(const tal_t *ctx, if (option_anchor_outputs) { return scriptpubkey_p2wsh(ctx, anchor_to_remote_redeem(tmpctx, - remotekey)); + remotekey, + csv_lock)); } else { return scriptpubkey_p2wpkh(ctx, remotekey); } @@ -2649,7 +2651,8 @@ static void handle_our_unilateral(const struct tx_parts *tx, /* Figure out what direct to-them output looks like. */ script[REMOTE] = scriptpubkey_to_remote(tmpctx, - &keyset->other_payment_key); + &keyset->other_payment_key, + 1); /* Calculate all the HTLC scripts so we can match them */ htlc_scripts = derive_htlc_scripts(htlcs, LOCAL); @@ -3087,7 +3090,7 @@ static void handle_their_cheat(const struct tx_parts *tx, /* Figure out what direct to-us output looks like. */ script[LOCAL] = scriptpubkey_to_remote(tmpctx, - &keyset->other_payment_key); + &keyset->other_payment_key, 1); /* Calculate all the HTLC scripts so we can match them */ htlc_scripts = derive_htlc_scripts(htlcs, REMOTE); @@ -3369,7 +3372,7 @@ static void handle_their_unilateral(const struct tx_parts *tx, /* Figure out what direct to-us output looks like. */ script[LOCAL] = scriptpubkey_to_remote(tmpctx, - &keyset->other_payment_key); + &keyset->other_payment_key, 1); /* Calculate all the HTLC scripts so we can match them */ htlc_scripts = derive_htlc_scripts(htlcs, REMOTE); @@ -3624,7 +3627,8 @@ static void handle_unknown_commitment(const struct tx_parts *tx, /* Other possible local script is for option_static_remotekey */ local_scripts[1] = scriptpubkey_to_remote(tmpctx, - &basepoints[LOCAL].payment); + &basepoints[LOCAL].payment, + 1); for (size_t i = 0; i < tal_count(tx->outputs); i++) { struct tracked_output *out; From 659d3abdd64a7217664baaac1b458fb1cbf050ab Mon Sep 17 00:00:00 2001 From: niftynei Date: Wed, 16 Jun 2021 12:44:51 -0500 Subject: [PATCH 26/56] lease_rates: add csv lock to modify anchor scripts --- bitcoin/script.c | 40 +++++++++++++++++++++++---- bitcoin/script.h | 5 ++-- channeld/commit_tx.c | 6 +++- channeld/watchtower.c | 3 +- common/initial_channel.c | 1 + common/initial_commit_tx.c | 10 +++++-- common/initial_commit_tx.h | 2 ++ hsmd/libhsmd.c | 5 +++- onchaind/onchaind.c | 20 ++++++++------ onchaind/test/run-grind_feerate-bug.c | 1 + onchaind/test/run-grind_feerate.c | 1 + 11 files changed, 71 insertions(+), 23 deletions(-) diff --git a/bitcoin/script.c b/bitcoin/script.c index cbf45858b095..a63855ac6f15 100644 --- a/bitcoin/script.c +++ b/bitcoin/script.c @@ -14,6 +14,8 @@ /* To push 0-75 bytes onto stack. */ #define OP_PUSHBYTES(val) (val) +#define max(a, b) ((a) > (b) ? (a) : (b)) + /* Bitcoin's OP_HASH160 is RIPEMD(SHA256()) */ static void hash160(struct ripemd160 *redeemhash, const void *mem, size_t len) { @@ -353,15 +355,21 @@ u8 *anchor_to_remote_redeem(const tal_t *ctx, bool is_anchor_witness_script(const u8 *script, size_t script_len) { - if (script_len != 34 + 1 + 1 + 1) + size_t len = 34 + 1 + 1 + 1; + /* With option_will_fund, the pushbytes can be up to 2 bytes more + * + * OP_CHECKSIGVERIFY + * MAX(1, lease_end - blockheight) + * OP_CHECKSEQUENCEVERIFY + */ + if (script_len < len || script_len > len + 2) return false; if (script[0] != OP_PUSHBYTES(33)) return false; if (script[34] != OP_CHECKSIGVERIFY) return false; - if (script[35] != 0x51) - return false; - if (script[36] != OP_CHECKSEQUENCEVERIFY) + /* FIXME: check for push value */ + if (script[script_len - 1] != OP_CHECKSEQUENCEVERIFY) return false; return true; } @@ -521,7 +529,27 @@ u8 **bitcoin_witness_sig_and_element(const tal_t *ctx, * OP_ENDIF * OP_CHECKSIG */ -u8 *bitcoin_wscript_to_local(const tal_t *ctx, u16 to_self_delay, +/* BOLT- #3 + * ##### Leased channel (`option_will_fund`) + * If a `lease` applies to the channel, the `to_local` output of the `accepter` + * ensures the `leasor` funds are not spendable until the lease expires. + * + * In a leased channel, the `to_local` output that pays the `accepter` node + * is modified so that its CSV is equal to the greater of the + * `to_self_delay` or the `lease_end` - `blockheight`. + * + * OP_IF + * # Penalty transaction + * + * OP_ELSE + * MAX(`to_self_delay`, `lease_end` - `blockheight`) + * OP_CHECKSEQUENCEVERIFY + * OP_DROP + * + * OP_ENDIF + * OP_CHECKSIG + */ +u8 *bitcoin_wscript_to_local(const tal_t *ctx, u16 to_self_delay, u32 csv, const struct pubkey *revocation_pubkey, const struct pubkey *local_delayedkey) { @@ -529,7 +557,7 @@ u8 *bitcoin_wscript_to_local(const tal_t *ctx, u16 to_self_delay, add_op(&script, OP_IF); add_push_key(&script, revocation_pubkey); add_op(&script, OP_ELSE); - add_number(&script, to_self_delay); + add_number(&script, max(csv, to_self_delay)); add_op(&script, OP_CHECKSEQUENCEVERIFY); add_op(&script, OP_DROP); add_push_key(&script, local_delayedkey); diff --git a/bitcoin/script.h b/bitcoin/script.h index 351bbcda0e92..3566092224c9 100644 --- a/bitcoin/script.h +++ b/bitcoin/script.h @@ -67,7 +67,7 @@ u8 *scriptpubkey_p2wpkh_derkey(const tal_t *ctx, const u8 der[33]); u8 *scriptpubkey_witness_raw(const tal_t *ctx, u8 version, const u8 *wprog, size_t wprog_size); -/* To-remotekey with csv 1 delay. */ +/* To-remotekey with csv max(lease_expiry - blockheight, 1) delay. */ u8 *anchor_to_remote_redeem(const tal_t *ctx, const struct pubkey *remote_key, u32 csv_lock); @@ -91,8 +91,7 @@ u8 **bitcoin_witness_sig_and_element(const tal_t *ctx, const u8 *witnessscript); /* BOLT #3 to-local output */ -u8 *bitcoin_wscript_to_local(const tal_t *ctx, - u16 to_self_delay, +u8 *bitcoin_wscript_to_local(const tal_t *ctx, u16 to_self_delay, u32 csv, const struct pubkey *revocation_pubkey, const struct pubkey *local_delayedkey); diff --git a/channeld/commit_tx.c b/channeld/commit_tx.c index 77ad07c0b3b6..045f1a83369c 100644 --- a/channeld/commit_tx.c +++ b/channeld/commit_tx.c @@ -234,7 +234,10 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx, * output](#to_local-output). */ if (amount_msat_greater_eq_sat(self_pay, dust_limit)) { - u8 *wscript = to_self_wscript(tmpctx, to_self_delay,keyset); + u8 *wscript = to_self_wscript(tmpctx, + to_self_delay, + 1, /* FIXME: csv_lock */ + keyset); u8 *p2wsh = scriptpubkey_p2wsh(tx, wscript); struct amount_sat amount = amount_msat_to_sat_round_down(self_pay); @@ -275,6 +278,7 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx, * Otherwise, this output is a simple P2WPKH to `remotepubkey`. */ if (option_anchor_outputs) { + /* FIXME: use csv_lock */ scriptpubkey = scriptpubkey_p2wsh(tmpctx, anchor_to_remote_redeem(tmpctx, &keyset->other_payment_key, 1)); } else { diff --git a/channeld/watchtower.c b/channeld/watchtower.c index ded35186eddd..994f643d0980 100644 --- a/channeld/watchtower.c +++ b/channeld/watchtower.c @@ -63,7 +63,8 @@ penalty_tx_create(const tal_t *ctx, status_failed(STATUS_FAIL_INTERNAL_ERROR, "Failed deriving keyset"); - wscript = bitcoin_wscript_to_local(tmpctx, remote_to_self_delay, + /* FIXME: csv_lock */ + wscript = bitcoin_wscript_to_local(tmpctx, remote_to_self_delay, 1, &keyset.self_revocation_key, &keyset.self_delayed_payment_key); diff --git a/common/initial_channel.c b/common/initial_channel.c index 8270f4a1bf16..dc19ca062a92 100644 --- a/common/initial_channel.c +++ b/common/initial_channel.c @@ -120,6 +120,7 @@ struct bitcoin_tx *initial_channel_tx(const tal_t *ctx, 0 ^ channel->commitment_number_obscurer, direct_outputs, side, + 0, /* FIXME: csv lock? */ channel->option_anchor_outputs, err_reason); diff --git a/common/initial_commit_tx.c b/common/initial_commit_tx.c index 792b32be4130..593eaa5cc370 100644 --- a/common/initial_commit_tx.c +++ b/common/initial_commit_tx.c @@ -51,9 +51,10 @@ bool try_subtract_fee(enum side opener, enum side side, u8 *to_self_wscript(const tal_t *ctx, u16 to_self_delay, + u32 csv, const struct keyset *keyset) { - return bitcoin_wscript_to_local(ctx, to_self_delay, + return bitcoin_wscript_to_local(ctx, to_self_delay, csv, &keyset->self_revocation_key, &keyset->self_delayed_payment_key); } @@ -87,6 +88,7 @@ struct bitcoin_tx *initial_commit_tx(const tal_t *ctx, u64 obscured_commitment_number, struct wally_tx_output *direct_outputs[NUM_SIDES], enum side side, + u32 csv_lock, bool option_anchor_outputs, char** err_reason) { @@ -208,7 +210,9 @@ struct bitcoin_tx *initial_commit_tx(const tal_t *ctx, * output](#to_local-output). */ if (amount_msat_greater_eq_sat(self_pay, dust_limit)) { - u8 *wscript = to_self_wscript(tmpctx, to_self_delay, keyset); + u8 *wscript = to_self_wscript(tmpctx, + to_self_delay, csv_lock, + keyset); amount = amount_msat_to_sat_round_down(self_pay); int pos = bitcoin_tx_add_output( tx, scriptpubkey_p2wsh(tx, wscript), wscript, amount); @@ -242,7 +246,7 @@ struct bitcoin_tx *initial_commit_tx(const tal_t *ctx, amount = amount_msat_to_sat_round_down(other_pay); if (option_anchor_outputs) { scriptpubkey = scriptpubkey_p2wsh(tmpctx, - anchor_to_remote_redeem(tmpctx, &keyset->other_payment_key, 1)); + anchor_to_remote_redeem(tmpctx, &keyset->other_payment_key, csv_lock)); } else { scriptpubkey = scriptpubkey_p2wpkh(tmpctx, &keyset->other_payment_key); diff --git a/common/initial_commit_tx.h b/common/initial_commit_tx.h index 8ff4b0155dd4..90f7dbda426a 100644 --- a/common/initial_commit_tx.h +++ b/common/initial_commit_tx.h @@ -121,6 +121,7 @@ struct bitcoin_tx *initial_commit_tx(const tal_t *ctx, u64 obscured_commitment_number, struct wally_tx_output *direct_outputs[NUM_SIDES], enum side side, + u32 csv_lock, bool option_anchor_outputs, char** err_reason); @@ -134,6 +135,7 @@ bool try_subtract_fee(enum side opener, enum side side, * scriptpubkey_p2wsh(ctx, wscript) gives the scriptpubkey */ u8 *to_self_wscript(const tal_t *ctx, u16 to_self_delay, + u32 csv, const struct keyset *keyset); /* To-other is simply: scriptpubkey_p2wpkh(tx, keyset->other_payment_key) */ diff --git a/hsmd/libhsmd.c b/hsmd/libhsmd.c index 5d026fbe507c..b51433b55253 100644 --- a/hsmd/libhsmd.c +++ b/hsmd/libhsmd.c @@ -388,7 +388,10 @@ static void sign_our_inputs(struct utxo **utxos, struct wally_psbt *psbt) /* It's actually a P2WSH in this case. */ if (utxo->close_info && utxo->close_info->option_anchor_outputs) { - const u8 *wscript = anchor_to_remote_redeem(tmpctx, &pubkey, 1); + const u8 *wscript + = anchor_to_remote_redeem(tmpctx, + &pubkey, + 1); /* FIXME: lease csv ? */ psbt_input_set_witscript(psbt, j, wscript); psbt_input_set_wit_utxo(psbt, j, scriptpubkey_p2wsh(psbt, wscript), diff --git a/onchaind/onchaind.c b/onchaind/onchaind.c index 2cc8f01f3e30..71f56981d6f6 100644 --- a/onchaind/onchaind.c +++ b/onchaind/onchaind.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -2644,15 +2645,15 @@ static void handle_our_unilateral(const struct tx_parts *tx, type_to_string(tmpctx, struct pubkey, &keyset->other_htlc_key)); - local_wscript = to_self_wscript(tmpctx, to_self_delay[LOCAL], keyset); + local_wscript = to_self_wscript(tmpctx, to_self_delay[LOCAL], + 1, keyset); /* Figure out what to-us output looks like. */ script[LOCAL] = scriptpubkey_p2wsh(tmpctx, local_wscript); /* Figure out what direct to-them output looks like. */ script[REMOTE] = scriptpubkey_to_remote(tmpctx, - &keyset->other_payment_key, - 1); + &keyset->other_payment_key, 1); /* Calculate all the HTLC scripts so we can match them */ htlc_scripts = derive_htlc_scripts(htlcs, LOCAL); @@ -2866,7 +2867,8 @@ static void handle_our_unilateral(const struct tx_parts *tx, /* We produce individual penalty txs. It's less efficient, but avoids them * using HTLC txs to block our penalties for long enough to pass the CSV * delay */ -static void steal_to_them_output(struct tracked_output *out, bool is_replay) +static void steal_to_them_output(struct tracked_output *out, + u32 csv, bool is_replay) { u8 *wscript; struct bitcoin_tx *tx; @@ -2879,7 +2881,7 @@ static void steal_to_them_output(struct tracked_output *out, bool is_replay) * * 1 */ - wscript = bitcoin_wscript_to_local(tmpctx, to_self_delay[REMOTE], + wscript = bitcoin_wscript_to_local(tmpctx, to_self_delay[REMOTE], csv, &keyset->self_revocation_key, &keyset->self_delayed_payment_key); @@ -3083,7 +3085,8 @@ static void handle_their_cheat(const struct tx_parts *tx, static_remotekey_start[LOCAL], static_remotekey_start[REMOTE]); - remote_wscript = to_self_wscript(tmpctx, to_self_delay[REMOTE], keyset); + remote_wscript = to_self_wscript(tmpctx, to_self_delay[REMOTE], + 1, keyset); /* Figure out what to-them output looks like. */ script[REMOTE] = scriptpubkey_p2wsh(tmpctx, remote_wscript); @@ -3176,7 +3179,7 @@ static void handle_their_cheat(const struct tx_parts *tx, amt, DELAYED_CHEAT_OUTPUT_TO_THEM, NULL, NULL, NULL); - steal_to_them_output(out, is_replay); + steal_to_them_output(out, 1, is_replay); script[REMOTE] = NULL; add_amt(&total_outs, amt); continue; @@ -3365,7 +3368,8 @@ static void handle_their_unilateral(const struct tx_parts *tx, type_to_string(tmpctx, struct pubkey, &keyset->other_htlc_key)); - remote_wscript = to_self_wscript(tmpctx, to_self_delay[REMOTE], keyset); + remote_wscript = to_self_wscript(tmpctx, to_self_delay[REMOTE], + 1, keyset); /* Figure out what to-them output looks like. */ script[REMOTE] = scriptpubkey_p2wsh(tmpctx, remote_wscript); diff --git a/onchaind/test/run-grind_feerate-bug.c b/onchaind/test/run-grind_feerate-bug.c index f6a77c2ecb62..8c44c52eded5 100644 --- a/onchaind/test/run-grind_feerate-bug.c +++ b/onchaind/test/run-grind_feerate-bug.c @@ -213,6 +213,7 @@ void subdaemon_setup(int argc UNNEEDED, char *argv[]) /* Generated stub for to_self_wscript */ u8 *to_self_wscript(const tal_t *ctx UNNEEDED, u16 to_self_delay UNNEEDED, + u32 csv UNNEEDED, const struct keyset *keyset UNNEEDED) { fprintf(stderr, "to_self_wscript called!\n"); abort(); } /* Generated stub for towire */ diff --git a/onchaind/test/run-grind_feerate.c b/onchaind/test/run-grind_feerate.c index 0a9b3d4ca945..c89ecef9ed0d 100644 --- a/onchaind/test/run-grind_feerate.c +++ b/onchaind/test/run-grind_feerate.c @@ -230,6 +230,7 @@ void subdaemon_setup(int argc UNNEEDED, char *argv[]) /* Generated stub for to_self_wscript */ u8 *to_self_wscript(const tal_t *ctx UNNEEDED, u16 to_self_delay UNNEEDED, + u32 csv UNNEEDED, const struct keyset *keyset UNNEEDED) { fprintf(stderr, "to_self_wscript called!\n"); abort(); } /* Generated stub for towire */ From 96fcb0788af3fa3fbd1acfc657b1d7eb2479c338 Mon Sep 17 00:00:00 2001 From: niftynei Date: Wed, 16 Jun 2021 12:56:36 -0500 Subject: [PATCH 27/56] lease_rates: pass in 'lease_expiry' and 'csv' to commitments/channel --- channeld/channeld.c | 1 + channeld/full_channel.c | 2 ++ channeld/full_channel.h | 2 ++ channeld/test/run-full_channel.c | 2 ++ common/initial_channel.c | 5 ++++- common/initial_channel.h | 5 +++++ common/utxo.c | 2 ++ common/utxo.h | 1 + devtools/mkcommit.c | 1 + hsmd/libhsmd.c | 2 +- openingd/dualopend.c | 4 ++++ openingd/openingd.c | 2 ++ 12 files changed, 27 insertions(+), 2 deletions(-) diff --git a/channeld/channeld.c b/channeld/channeld.c index d94b0c0752b0..35b430756662 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -3525,6 +3525,7 @@ static void init_channel(struct peer *peer) &funding_txid, funding_txout, minimum_depth, + 0, /* FIXME: channel lease_expiry */ funding, local_msat, take(fee_states), diff --git a/channeld/full_channel.c b/channeld/full_channel.c index 59665eeb4136..3418dee0651f 100644 --- a/channeld/full_channel.c +++ b/channeld/full_channel.c @@ -95,6 +95,7 @@ struct channel *new_full_channel(const tal_t *ctx, const struct bitcoin_txid *funding_txid, unsigned int funding_txout, u32 minimum_depth, + u32 lease_expiry, struct amount_sat funding, struct amount_msat local_msat, const struct fee_states *fee_states, @@ -113,6 +114,7 @@ struct channel *new_full_channel(const tal_t *ctx, funding_txid, funding_txout, minimum_depth, + lease_expiry, funding, local_msat, fee_states, diff --git a/channeld/full_channel.h b/channeld/full_channel.h index e23deb3b11fa..c7151ddb6fd2 100644 --- a/channeld/full_channel.h +++ b/channeld/full_channel.h @@ -17,6 +17,7 @@ struct existing_htlc; * @funding_txid: The commitment transaction id. * @funding_txout: The commitment transaction output number. * @minimum_depth: The minimum confirmations needed for funding transaction. + * @lease_expiry: The block the lease on this channel expires at; 0 if no lease. * @funding: The commitment transaction amount. * @local_msat: The amount for the local side (remainder goes to remote) * @fee_states: The fee update states. @@ -37,6 +38,7 @@ struct channel *new_full_channel(const tal_t *ctx, const struct bitcoin_txid *funding_txid, unsigned int funding_txout, u32 minimum_depth, + u32 lease_expiry, struct amount_sat funding, struct amount_msat local_msat, const struct fee_states *fee_states, diff --git a/channeld/test/run-full_channel.c b/channeld/test/run-full_channel.c index 89eb791e758b..e21350a6478b 100644 --- a/channeld/test/run-full_channel.c +++ b/channeld/test/run-full_channel.c @@ -481,6 +481,7 @@ int main(int argc, const char *argv[]) derive_channel_id(&cid, &funding_txid, funding_output_index); lchannel = new_full_channel(tmpctx, &cid, &funding_txid, funding_output_index, 0, + 0, /* No channel lease */ funding_amount, to_local, take(new_fee_states(NULL, LOCAL, &feerate_per_kw[LOCAL])), @@ -492,6 +493,7 @@ int main(int argc, const char *argv[]) false, false, LOCAL); rchannel = new_full_channel(tmpctx, &cid, &funding_txid, funding_output_index, 0, + 0, /* No channel lease */ funding_amount, to_remote, take(new_fee_states(NULL, REMOTE, &feerate_per_kw[REMOTE])), diff --git a/common/initial_channel.c b/common/initial_channel.c index dc19ca062a92..44198efe41ea 100644 --- a/common/initial_channel.c +++ b/common/initial_channel.c @@ -20,6 +20,7 @@ struct channel *new_initial_channel(const tal_t *ctx, const struct bitcoin_txid *funding_txid, unsigned int funding_txout, u32 minimum_depth, + u32 lease_expiry, struct amount_sat funding, struct amount_msat local_msatoshi, const struct fee_states *fee_states TAKES, @@ -41,6 +42,7 @@ struct channel *new_initial_channel(const tal_t *ctx, channel->funding_txout = funding_txout; channel->funding = funding; channel->minimum_depth = minimum_depth; + channel->lease_expiry = lease_expiry; if (!amount_sat_sub_msat(&remote_msatoshi, channel->funding, local_msatoshi)) return tal_free(channel); @@ -120,7 +122,8 @@ struct bitcoin_tx *initial_channel_tx(const tal_t *ctx, 0 ^ channel->commitment_number_obscurer, direct_outputs, side, - 0, /* FIXME: csv lock? */ + /* FIXME: is not the csv lock ?! */ + channel->lease_expiry, channel->option_anchor_outputs, err_reason); diff --git a/common/initial_channel.h b/common/initial_channel.h index 09f2e86a16b2..187286ff095f 100644 --- a/common/initial_channel.h +++ b/common/initial_channel.h @@ -70,6 +70,9 @@ struct channel { /* Is this using option_anchor_outputs? */ bool option_anchor_outputs; + + /* When the lease expires for the funds in this channel */ + u32 lease_expiry; }; /** @@ -79,6 +82,7 @@ struct channel { * @funding_txid: The commitment transaction id. * @funding_txout: The commitment transaction output number. * @minimum_depth: The minimum confirmations needed for funding transaction. + * @lease_expiry: Block the lease expires * @funding_satoshis: The commitment transaction amount. * @local_msatoshi: The amount for the local side (remainder goes to remote) * @fee_states: The fee update states. @@ -99,6 +103,7 @@ struct channel *new_initial_channel(const tal_t *ctx, const struct bitcoin_txid *funding_txid, unsigned int funding_txout, u32 minimum_depth, + u32 lease_expiry, struct amount_sat funding, struct amount_msat local_msatoshi, const struct fee_states *fee_states TAKES, diff --git a/common/utxo.c b/common/utxo.c index b561d42b9733..22777320555c 100644 --- a/common/utxo.c +++ b/common/utxo.c @@ -31,6 +31,7 @@ void towire_utxo(u8 **pptr, const struct utxo *utxo) if (utxo->close_info->commitment_point) towire_pubkey(pptr, utxo->close_info->commitment_point); towire_bool(pptr, utxo->close_info->option_anchor_outputs); + towire_u32(pptr, utxo->close_info->csv); } } @@ -59,6 +60,7 @@ struct utxo *fromwire_utxo(const tal_t *ctx, const u8 **ptr, size_t *max) utxo->close_info->commitment_point = NULL; utxo->close_info->option_anchor_outputs = fromwire_bool(ptr, max); + utxo->close_info->csv = fromwire_u32(ptr, max); } else { utxo->close_info = NULL; } diff --git a/common/utxo.h b/common/utxo.h index bcf07fb6f3ca..2f3c63764b8f 100644 --- a/common/utxo.h +++ b/common/utxo.h @@ -20,6 +20,7 @@ struct unilateral_close_info { bool option_anchor_outputs; /* NULL if this is an option_static_remotekey commitment */ struct pubkey *commitment_point; + u32 csv; }; /* Possible states for tracked outputs in the database. Not sure yet diff --git a/devtools/mkcommit.c b/devtools/mkcommit.c index 2b1eccaf0816..8f0ba013a605 100644 --- a/devtools/mkcommit.c +++ b/devtools/mkcommit.c @@ -394,6 +394,7 @@ int main(int argc, char *argv[]) channel = new_full_channel(NULL, &cid, &funding_txid, funding_outnum, 1, + 0, /* Defaults to no lease */ funding_amount, local_msat, take(new_fee_states(NULL, fee_payer, diff --git a/hsmd/libhsmd.c b/hsmd/libhsmd.c index b51433b55253..b1db7aac5474 100644 --- a/hsmd/libhsmd.c +++ b/hsmd/libhsmd.c @@ -391,7 +391,7 @@ static void sign_our_inputs(struct utxo **utxos, struct wally_psbt *psbt) const u8 *wscript = anchor_to_remote_redeem(tmpctx, &pubkey, - 1); /* FIXME: lease csv ? */ + utxo->close_info->csv); psbt_input_set_witscript(psbt, j, wscript); psbt_input_set_wit_utxo(psbt, j, scriptpubkey_p2wsh(psbt, wscript), diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 3ae0328f5131..759d0406b9c2 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -1647,6 +1647,7 @@ static void revert_channel_state(struct state *state) &tx_state->funding_txid, tx_state->funding_txout, state->minimum_depth, + tx_state->lease_expiry, total, our_msats, take(new_fee_states( @@ -1743,6 +1744,7 @@ static u8 *accepter_commits(struct state *state, &tx_state->funding_txid, tx_state->funding_txout, state->minimum_depth, + tx_state->lease_expiry, total, our_msats, take(new_fee_states( @@ -2334,6 +2336,7 @@ static u8 *opener_commits(struct state *state, &tx_state->funding_txid, tx_state->funding_txout, state->minimum_depth, + tx_state->lease_expiry, total, our_msats, take(new_fee_states(NULL, LOCAL, @@ -3745,6 +3748,7 @@ int main(int argc, char *argv[]) &state->tx_state->funding_txid, state->tx_state->funding_txout, state->minimum_depth, + state->tx_state->lease_expiry, total_funding, our_msat, fee_states, diff --git a/openingd/openingd.c b/openingd/openingd.c index 7a0d1bdeed2d..a96024ffdc36 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -510,6 +510,7 @@ static bool funder_finalize_channel_setup(struct state *state, &state->funding_txid, state->funding_txout, state->minimum_depth, + 0, /* No lease lock */ state->funding, local_msat, take(new_fee_states(NULL, LOCAL, @@ -1000,6 +1001,7 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) &state->funding_txid, state->funding_txout, state->minimum_depth, + 0, /* No channel lease */ state->funding, state->push_msat, take(new_fee_states(NULL, REMOTE, From 9ed0d22236d4258d9995c6d0379007e50298cb90 Mon Sep 17 00:00:00 2001 From: niftynei Date: Wed, 16 Jun 2021 13:09:32 -0500 Subject: [PATCH 28/56] onchaind: add recovery scans for option-will-fund option_will_fund changes the to_remote/to_local commitment tx outputs by altering the CSV lock for leased channels. We need to grind/scan for these outputs now, provided the defaults don't work. --- onchaind/onchaind.c | 536 ++++++++++++++++++++++++++++++++------------ 1 file changed, 388 insertions(+), 148 deletions(-) diff --git a/onchaind/onchaind.c b/onchaind/onchaind.c index 71f56981d6f6..bc32a0b8d3e0 100644 --- a/onchaind/onchaind.c +++ b/onchaind/onchaind.c @@ -36,6 +36,7 @@ /* stdin == requests */ #define REQ_FD STDIN_FILENO #define HSM_FD 3 +#define max(a, b) ((a) > (b) ? (a) : (b)) /* Required in various places: keys for commitment transaction. */ static const struct keyset *keyset; @@ -2583,12 +2584,66 @@ static u8 *scriptpubkey_to_remote(const tal_t *ctx, } } +static void our_unilateral_to_us(struct tracked_output ***outs, + const struct tx_parts *tx, + u32 tx_blockheight, + size_t index, + struct amount_sat amt, + u16 sequence, + const u8 *local_scriptpubkey, + const u8 *local_wscript, + bool is_replay) +{ + struct bitcoin_tx *to_us; + struct tracked_output *out; + enum tx_type tx_type = OUR_DELAYED_RETURN_TO_WALLET; + + /* BOLT #5: + * + * A node: + * - upon discovering its *local commitment + * transaction*: + * - SHOULD spend the `to_local` output to a + * convenient address. + * - MUST wait until the `OP_CHECKSEQUENCEVERIFY` + * delay has passed (as specified by the remote + * node's `to_self_delay` field) before spending + * the output. + */ + out = new_tracked_output(outs, &tx->txid, tx_blockheight, + OUR_UNILATERAL, index, + amt, + DELAYED_OUTPUT_TO_US, + NULL, NULL, NULL); + /* BOLT #3: + * + * The output is spent by an input with + * `nSequence` field set to `to_self_delay` (which can + * only be valid after that duration has passed) and + * witness: + * + * <> + */ + to_us = tx_to_us(out, delayed_payment_to_us, out, + sequence, 0, NULL, 0, + local_wscript, &tx_type, + delayed_to_us_feerate); + + /* BOLT #5: + * + * Note: if the output is spent (as recommended), the + * output is *resolved* by the spending transaction + */ + propose_resolution(out, to_us, sequence, tx_type, is_replay); +} + static void handle_our_unilateral(const struct tx_parts *tx, u32 tx_blockheight, const struct basepoints basepoints[NUM_SIDES], const struct htlc_stub *htlcs, const bool *tell_if_missing, const bool *tell_immediately, + const enum side opener, const struct bitcoin_signature *remote_htlc_sigs, struct tracked_output **outs, bool is_replay) @@ -2701,47 +2756,10 @@ static void handle_our_unilateral(const struct tx_parts *tx, } else if (script[LOCAL] && wally_tx_output_scripteq(tx->outputs[i], script[LOCAL])) { - struct bitcoin_tx *to_us; - enum tx_type tx_type = OUR_DELAYED_RETURN_TO_WALLET; - - /* BOLT #5: - * - * A node: - * - upon discovering its *local commitment - * transaction*: - * - SHOULD spend the `to_local` output to a - * convenient address. - * - MUST wait until the `OP_CHECKSEQUENCEVERIFY` - * delay has passed (as specified by the remote - * node's `to_self_delay` field) before spending - * the output. - */ - out = new_tracked_output(&outs, &tx->txid, tx_blockheight, - OUR_UNILATERAL, i, - amt, - DELAYED_OUTPUT_TO_US, - NULL, NULL, NULL); - /* BOLT #3: - * - * The output is spent by an input with - * `nSequence` field set to `to_self_delay` (which can - * only be valid after that duration has passed) and - * witness: - * - * <> - */ - to_us = tx_to_us(out, delayed_payment_to_us, out, - to_self_delay[LOCAL], 0, NULL, 0, - local_wscript, &tx_type, - delayed_to_us_feerate); - - /* BOLT #5: - * - * Note: if the output is spent (as recommended), the - * output is *resolved* by the spending transaction - */ - propose_resolution(out, to_us, to_self_delay[LOCAL], - tx_type, is_replay); + our_unilateral_to_us(&outs, tx, tx_blockheight, + i, amt, to_self_delay[LOCAL], + script[LOCAL], + local_wscript, is_replay); script[LOCAL] = NULL; add_amt(&our_outs, amt); @@ -2798,6 +2816,81 @@ static void handle_our_unilateral(const struct tx_parts *tx, matches = match_htlc_output(tmpctx, tx->outputs[i], htlc_scripts); /* FIXME: limp along when this happens! */ if (tal_count(matches) == 0) { + bool found = false; + + /* Maybe they're using option_will_fund? */ + if (opener == REMOTE && script[LOCAL]) { + status_debug("Grinding for our to_local"); + /* We already tried `1` */ + for (size_t csv = 2; + csv <= LEASE_RATE_DURATION; + csv++) { + + local_wscript + = to_self_wscript(tmpctx, + to_self_delay[LOCAL], + csv, keyset); + + script[LOCAL] + = scriptpubkey_p2wsh(tmpctx, + local_wscript); + if (!wally_tx_output_scripteq( + tx->outputs[i], + script[LOCAL])) + continue; + + our_unilateral_to_us(&outs, tx, + tx_blockheight, + i, amt, + max(to_self_delay[LOCAL], csv), + script[LOCAL], + local_wscript, + is_replay); + + script[LOCAL] = NULL; + add_amt(&our_outs, amt); + found = true; + break; + } + } else if (opener == LOCAL && script[REMOTE]) { + status_debug("Grinding for to_remote (ours)"); + /* We already tried `1` */ + for (size_t csv = 2; + csv <= LEASE_RATE_DURATION; + csv++) { + + script[REMOTE] + = scriptpubkey_to_remote(tmpctx, + &keyset->other_payment_key, + csv); + + if (!wally_tx_output_scripteq(tx->outputs[i], script[REMOTE])) + continue; + + /* BOLT #5: + * + * - MAY ignore the `to_remote` output. + * - Note: No action is required by the local + * node, as `to_remote` is considered *resolved* + * by the commitment transaction itself. + */ + out = new_tracked_output(&outs, &tx->txid, tx_blockheight, + OUR_UNILATERAL, i, + amt, + OUTPUT_TO_THEM, + NULL, NULL, NULL); + ignore_output(out); + script[REMOTE] = NULL; + add_amt(&their_outs, amt); + found = true; + break; + } + } + + + if (found) + continue; + onchain_annotate_txout(&tx->txid, i, TX_CHANNEL_PENALTY | TX_THEIRS); status_failed(STATUS_FAIL_INTERNAL_ERROR, "Could not find resolution for output %zu", @@ -2919,7 +3012,8 @@ static void tell_wallet_to_remote(const struct tx_parts *tx, u32 tx_blockheight, const u8 *scriptpubkey, const struct pubkey *per_commit_point, - bool option_static_remotekey) + bool option_static_remotekey, + u32 csv_lock) { struct amount_asset asset = wally_tx_output_get_amount(tx->outputs[outnum]); struct amount_sat amt; @@ -2971,6 +3065,47 @@ static void update_ledger_cheat(const struct bitcoin_txid *txid, blockheight, amt, true))); } +static void their_unilateral_local(struct tracked_output ***outs, + const struct tx_parts *tx, + u32 tx_blockheight, + size_t index, + struct amount_sat amt, + const u8 *local_scriptpubkey, + enum tx_type tx_type, + bool is_replay, + u32 csv_lock) +{ + struct tracked_output *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, + tx_type, + index, amt, + OUTPUT_TO_US, + NULL, NULL, + NULL); + ignore_output(out); + + if (!is_replay) + record_channel_withdrawal(&tx->txid, tx_blockheight, out); + + tell_wallet_to_remote(tx, index, + tx_blockheight, + local_scriptpubkey, + remote_per_commitment_point, + commit_num >= static_remotekey_start[REMOTE], + csv_lock); +} + + /* BOLT #5: * * If any node tries to cheat by broadcasting an outdated commitment @@ -2985,6 +3120,7 @@ static void handle_their_cheat(const struct tx_parts *tx, const struct htlc_stub *htlcs, const bool *tell_if_missing, const bool *tell_immediately, + const enum side opener, struct tracked_output **outs, bool is_replay) { @@ -3140,28 +3276,10 @@ static void handle_their_cheat(const struct tx_parts *tx, if (script[LOCAL] && wally_tx_output_scripteq(tx->outputs[i], script[LOCAL])) { - /* BOLT #5: - * - * - MAY take no action regarding the _local node's - * main output_, as this is a simple P2WPKH output - * to itself. - * - Note: this output is considered *resolved* by - * the commitment transaction itself. - */ - out = new_tracked_output(&outs, &tx->txid, tx_blockheight, - THEIR_REVOKED_UNILATERAL, - i, amt, - OUTPUT_TO_US, NULL, NULL, NULL); - ignore_output(out); - - if (!is_replay) - record_channel_withdrawal(&tx->txid, tx_blockheight, out); - - tell_wallet_to_remote(tx, i, - tx_blockheight, - script[LOCAL], - remote_per_commitment_point, - commit_num >= static_remotekey_start[REMOTE]); + their_unilateral_local(&outs, tx, tx_blockheight, + i, amt, script[LOCAL], + THEIR_REVOKED_UNILATERAL, + is_replay, 1); script[LOCAL] = NULL; add_amt(&total_outs, amt); continue; @@ -3214,7 +3332,71 @@ 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_broken("Could not find resolution for output %zu: did *we* cheat?", i); + bool found = false; + if (opener == REMOTE && script[LOCAL]) { + status_debug("Grinding for commitment to_remote" + " (ours)"); + /* We already tried `1` */ + for (size_t csv = 2; + csv <= LEASE_RATE_DURATION; + csv++) { + script[LOCAL] + = scriptpubkey_to_remote(tmpctx, + &keyset->other_payment_key, + csv); + if (!wally_tx_output_scripteq( + tx->outputs[i], + script[LOCAL])) + continue; + + their_unilateral_local(&outs, tx, + tx_blockheight, + i, amt, + script[LOCAL], + THEIR_REVOKED_UNILATERAL, + is_replay, + csv); + script[LOCAL] = NULL; + add_amt(&total_outs, amt); + found = true; + break; + } + } else if (opener == LOCAL && script[REMOTE]) { + status_debug("Grinding for commitment to_local" + " (theirs)"); + for (size_t csv = 2; + csv <= LEASE_RATE_DURATION; + csv++) { + remote_wscript + = to_self_wscript(tmpctx, + to_self_delay[REMOTE], + csv, keyset); + script[REMOTE] + = scriptpubkey_p2wsh(tmpctx, + remote_wscript); + + + if (!wally_tx_output_scripteq(tx->outputs[i], script[REMOTE])) + continue; + + out = new_tracked_output(&outs, &tx->txid, tx_blockheight, + THEIR_REVOKED_UNILATERAL, i, + amt, + DELAYED_CHEAT_OUTPUT_TO_THEM, + NULL, NULL, NULL); + steal_to_them_output(out, csv, + is_replay); + script[REMOTE] = NULL; + add_amt(&total_outs, amt); + found = true; + break; + } + } + + if (!found) + status_broken("Could not find resolution" + " for output %zu: did" + " *we* cheat?", i); continue; } @@ -3283,6 +3465,7 @@ static void handle_their_unilateral(const struct tx_parts *tx, const struct htlc_stub *htlcs, const bool *tell_if_missing, const bool *tell_immediately, + const enum side opener, struct tracked_output **outs, bool is_replay) { @@ -3368,26 +3551,9 @@ static void handle_their_unilateral(const struct tx_parts *tx, type_to_string(tmpctx, struct pubkey, &keyset->other_htlc_key)); - remote_wscript = to_self_wscript(tmpctx, to_self_delay[REMOTE], - 1, keyset); - - /* Figure out what to-them output looks like. */ - script[REMOTE] = scriptpubkey_p2wsh(tmpctx, remote_wscript); - - /* Figure out what direct to-us output looks like. */ - script[LOCAL] = scriptpubkey_to_remote(tmpctx, - &keyset->other_payment_key, 1); - /* Calculate all the HTLC scripts so we can match them */ htlc_scripts = derive_htlc_scripts(htlcs, REMOTE); - status_debug("Script to-them: %u: %s (%s)", - to_self_delay[REMOTE], - tal_hex(tmpctx, script[REMOTE]), - tal_hex(tmpctx, remote_wscript)); - status_debug("Script to-me: %s", - tal_hex(tmpctx, script[LOCAL])); - get_anchor_scriptpubkeys(tmpctx, anchor); for (i = 0; i < tal_count(tx->outputs); i++) { @@ -3398,6 +3564,21 @@ static void handle_their_unilateral(const struct tx_parts *tx, tx->outputs[i]->script_len)); } + remote_wscript = to_self_wscript(tmpctx, to_self_delay[REMOTE], + 1, keyset); + script[REMOTE] = scriptpubkey_p2wsh(tmpctx, remote_wscript); + + script[LOCAL] = scriptpubkey_to_remote(tmpctx, + &keyset->other_payment_key, + 1); + + status_debug("Script to-them: %u: %s (%s)", + to_self_delay[REMOTE], + tal_hex(tmpctx, script[REMOTE]), + tal_hex(tmpctx, remote_wscript)); + status_debug("Script to-me: %s", + tal_hex(tmpctx, script[LOCAL])); + for (i = 0; i < tal_count(tx->outputs); i++) { struct tracked_output *out; const size_t *matches; @@ -3421,28 +3602,11 @@ static void handle_their_unilateral(const struct tx_parts *tx, } else if (script[LOCAL] && wally_tx_output_scripteq(tx->outputs[i], script[LOCAL])) { - /* 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, - THEIR_UNILATERAL, - i, amt, - OUTPUT_TO_US, NULL, NULL, NULL); - ignore_output(out); - - if (!is_replay) - record_channel_withdrawal(&tx->txid, tx_blockheight, out); + their_unilateral_local(&outs, tx, tx_blockheight, + i, amt, script[LOCAL], + THEIR_UNILATERAL, + is_replay, 1); - tell_wallet_to_remote(tx, i, - tx_blockheight, - script[LOCAL], - remote_per_commitment_point, - commit_num >= static_remotekey_start[REMOTE]); script[LOCAL] = NULL; add_amt(&our_outs, amt); continue; @@ -3496,10 +3660,75 @@ static void handle_their_unilateral(const struct tx_parts *tx, } matches = match_htlc_output(tmpctx, tx->outputs[i], htlc_scripts); - if (tal_count(matches) == 0) + if (tal_count(matches) == 0) { + bool found = false; + + /* We need to hunt for it (option_will_fund?) */ + if (opener == REMOTE && script[LOCAL]) { + status_debug("Grinding for commitment to_remote" + " (ours)"); + /* We already tried `1` */ + for (size_t csv = 2; + csv <= LEASE_RATE_DURATION; + csv++) { + script[LOCAL] + = scriptpubkey_to_remote(tmpctx, + &keyset->other_payment_key, + csv); + if (!wally_tx_output_scripteq( + tx->outputs[i], + script[LOCAL])) + continue; + + their_unilateral_local(&outs, tx, + tx_blockheight, + i, amt, + script[LOCAL], + THEIR_UNILATERAL, + is_replay, csv); + script[LOCAL] = NULL; + add_amt(&our_outs, amt); + found = true; + break; + } + } else if (opener == LOCAL && script[REMOTE]) { + status_debug("Grinding for commitment to_local" + " (theirs)"); + /* We already tried `1` */ + for (size_t csv = 2; + csv <= LEASE_RATE_DURATION; + csv++) { + remote_wscript + = to_self_wscript(tmpctx, + to_self_delay[REMOTE], + csv, keyset); + script[REMOTE] + = scriptpubkey_p2wsh(tmpctx, + remote_wscript); + + + if (!wally_tx_output_scripteq(tx->outputs[i], script[REMOTE])) + continue; + + out = new_tracked_output(&outs, &tx->txid, tx_blockheight, + THEIR_UNILATERAL, i, + amt, + DELAYED_OUTPUT_TO_THEM, + NULL, NULL, NULL); + ignore_output(out); + add_amt(&their_outs, amt); + found = true; + break; + } + } + + if (found) + continue; + status_failed(STATUS_FAIL_INTERNAL_ERROR, "Could not find resolution for output %zu", i); + } if (matches_direction(matches, htlcs) == LOCAL) { /* BOLT #5: @@ -3629,59 +3858,66 @@ static void handle_unknown_commitment(const struct tx_parts *tx, local_scripts[0] = NULL; } - /* Other possible local script is for option_static_remotekey */ - local_scripts[1] = scriptpubkey_to_remote(tmpctx, - &basepoints[LOCAL].payment, - 1); + /* For option_will_fund, we need to figure out what CSV lock was used */ + for (size_t csv = 1; csv <= LEASE_RATE_DURATION; csv++) { - 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; + /* Other possible local script is for option_static_remotekey */ + local_scripts[1] = scriptpubkey_to_remote(tmpctx, + &basepoints[LOCAL].payment, + csv); - assert(amount_asset_is_main(&asset)); - amt = amount_asset_to_sat(&asset); + 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; - /* 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; + assert(amount_asset_is_main(&asset)); + amt = amount_asset_to_sat(&asset); + + /* 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; - /* 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); + /* 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); - if (!is_replay) - record_channel_withdrawal(&tx->txid, tx_blockheight, out); + if (!is_replay) + record_channel_withdrawal(&tx->txid, tx_blockheight, out); - add_amt(&amt_salvaged, amt); + 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; + tell_wallet_to_remote(tx, i, + tx_blockheight, + local_scripts[which_script], + possible_remote_per_commitment_point, + which_script == 1, + csv); + local_scripts[0] = local_scripts[1] = NULL; + to_us_output = i; + goto script_found; + } } +script_found: if (to_us_output == -1) { status_broken("FUNDS LOST. Unknown commitment #%"PRIu64"!", commit_num); @@ -3870,6 +4106,7 @@ int main(int argc, char *argv[]) basepoints, htlcs, tell_if_missing, tell_immediately, + opener, remote_htlc_sigs, outs, open_is_replay); @@ -3888,6 +4125,7 @@ int main(int argc, char *argv[]) basepoints, htlcs, tell_if_missing, tell_immediately, + opener, outs, open_is_replay); /* BOLT #5: @@ -3907,6 +4145,7 @@ int main(int argc, char *argv[]) htlcs, tell_if_missing, tell_immediately, + opener, outs, open_is_replay); } else if (commit_num == revocations_received(&shachain) + 1) { @@ -3917,6 +4156,7 @@ int main(int argc, char *argv[]) htlcs, tell_if_missing, tell_immediately, + opener, outs, open_is_replay); } else { From 215869b75a69ca103a650fc4afd859ef446e0aa8 Mon Sep 17 00:00:00 2001 From: niftynei Date: Wed, 16 Jun 2021 20:28:18 -0500 Subject: [PATCH 29/56] lease_rates: persist channel's lease info --- common/initial_channel.c | 13 +- lightningd/channel.c | 24 ++- lightningd/channel.h | 30 +++- lightningd/dual_open_control.c | 69 ++++++-- lightningd/opening_control.c | 3 +- lightningd/peer_control.c | 7 + openingd/dualopend.c | 102 +++++++++--- openingd/dualopend_wire.csv | 8 + openingd/dualopend_wiregen.c | 46 +++++- openingd/dualopend_wiregen.h | 10 +- wallet/db.c | 8 + wallet/db_postgres_sqlgen.c | 66 ++++++-- wallet/db_sqlite3_sqlgen.c | 66 ++++++-- wallet/statements_gettextgen.po | 276 ++++++++++++++++++-------------- wallet/test/run-wallet.c | 10 +- wallet/wallet.c | 70 +++++++- 16 files changed, 612 insertions(+), 196 deletions(-) diff --git a/common/initial_channel.c b/common/initial_channel.c index 44198efe41ea..4c8c63c169e6 100644 --- a/common/initial_channel.c +++ b/common/initial_channel.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -89,6 +90,7 @@ struct bitcoin_tx *initial_channel_tx(const tal_t *ctx, { struct keyset keyset; struct bitcoin_tx *init_tx; + u32 csv_lock; /* This assumes no HTLCs! */ assert(!channel->htlcs); @@ -102,6 +104,13 @@ struct bitcoin_tx *initial_channel_tx(const tal_t *ctx, return NULL; } + /* Figure out the csv_lock (if there's a lease) */ + if (channel->lease_expiry == 0) + csv_lock = 1; + else + /* FIXME: */ + csv_lock = 1; + *wscript = bitcoin_redeem_2of2(ctx, &channel->funding_pubkey[side], &channel->funding_pubkey[!side]); @@ -121,9 +130,7 @@ struct bitcoin_tx *initial_channel_tx(const tal_t *ctx, channel->config[!side].channel_reserve, 0 ^ channel->commitment_number_obscurer, direct_outputs, - side, - /* FIXME: is not the csv lock ?! */ - channel->lease_expiry, + side, csv_lock, channel->option_anchor_outputs, err_reason); diff --git a/lightningd/channel.c b/lightningd/channel.c index 074a058efb18..1a5d2ee1d879 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -160,7 +160,11 @@ new_inflight(struct channel *channel, struct amount_sat our_funds, struct wally_psbt *psbt STEALS, struct bitcoin_tx *last_tx, - const struct bitcoin_signature last_sig) + const struct bitcoin_signature last_sig, + const u32 lease_expiry, + const secp256k1_ecdsa_signature *lease_commit_sig, + const u32 lease_chan_max_msat, + const u16 lease_chan_max_ppt) { struct wally_psbt *last_tx_psbt_clone; struct channel_inflight *inflight @@ -185,6 +189,11 @@ new_inflight(struct channel *channel, inflight->last_sig = last_sig; inflight->tx_broadcast = false; + inflight->lease_expiry = lease_expiry; + inflight->lease_commit_sig = tal_dup(inflight, secp256k1_ecdsa_signature, lease_commit_sig); + inflight->lease_chan_max_msat = lease_chan_max_msat; + inflight->lease_chan_max_ppt = lease_chan_max_ppt; + list_add_tail(&channel->inflights, &inflight->list); tal_add_destructor(inflight, destroy_inflight); @@ -268,6 +277,8 @@ struct channel *new_unsaved_channel(struct peer *peer, channel->option_anchor_outputs = true; channel->future_per_commitment_point = NULL; + channel->lease_commit_sig = NULL; + /* No shachain yet */ channel->their_shachain.id = 0; shachain_init(&channel->their_shachain.chain); @@ -341,7 +352,11 @@ struct channel *new_channel(struct peer *peer, u64 dbid, enum side closer, enum state_change reason, /* NULL or stolen */ - const struct bitcoin_outpoint *shutdown_wrong_funding) + const struct bitcoin_outpoint *shutdown_wrong_funding, + u32 lease_expiry, + secp256k1_ecdsa_signature *lease_commit_sig STEALS, + u32 lease_chan_max_msat, + u16 lease_chan_max_ppt) { struct channel *channel = tal(peer->ld, struct channel); @@ -430,6 +445,11 @@ struct channel *new_channel(struct peer *peer, u64 dbid, channel->option_anchor_outputs = option_anchor_outputs; channel->forgets = tal_arr(channel, struct command *, 0); + channel->lease_expiry = lease_expiry; + channel->lease_commit_sig = tal_steal(channel, lease_commit_sig); + channel->lease_chan_max_msat = lease_chan_max_msat; + channel->lease_chan_max_ppt = lease_chan_max_ppt; + list_add_tail(&peer->channels, &channel->list); channel->rr_number = peer->ld->rr_counter++; tal_add_destructor(channel, destroy_channel); diff --git a/lightningd/channel.h b/lightningd/channel.h index 0ea0ca451a12..36c070ab3bfe 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -45,6 +45,12 @@ struct channel_inflight { /* Commitment tx and sigs */ struct bitcoin_tx *last_tx; struct bitcoin_signature last_sig; + + /* Channel lease infos */ + u32 lease_expiry; + secp256k1_ecdsa_signature *lease_commit_sig; + u32 lease_chan_max_msat; + u16 lease_chan_max_ppt; }; struct open_attempt { @@ -208,6 +214,18 @@ struct channel { /* Outstanding command for this channel, v2 only */ struct command *openchannel_signed_cmd; + + /* Block lease expires at, zero is no lease */ + u32 lease_expiry; + + /* Lease commitment, useful someone breaks their promise + * wrt channel fees */ + secp256k1_ecdsa_signature *lease_commit_sig; + + /* Lease commited maximum channel fee base msat */ + u32 lease_chan_max_msat; + /* Lease commited max part per thousandth channel fee (ppm * 1000) */ + u16 lease_chan_max_ppt; }; /* For v2 opens, a channel that has not yet been committed/saved to disk */ @@ -273,7 +291,11 @@ struct channel *new_channel(struct peer *peer, u64 dbid, enum side closer, enum state_change reason, /* NULL or stolen */ - const struct bitcoin_outpoint *shutdown_wrong_funding STEALS); + const struct bitcoin_outpoint *shutdown_wrong_funding STEALS, + u32 lease_expiry, + secp256k1_ecdsa_signature *lease_commit_sig STEALS, + u32 lease_chan_max_msat, + u16 lease_chan_max_ppt); /* new_inflight - Create a new channel_inflight for a channel */ struct channel_inflight * @@ -285,7 +307,11 @@ new_inflight(struct channel *channel, struct amount_sat our_funds, struct wally_psbt *funding_psbt STEALS, struct bitcoin_tx *last_tx STEALS, - const struct bitcoin_signature last_sig); + const struct bitcoin_signature last_sig, + const u32 lease_expiry, + const secp256k1_ecdsa_signature *lease_commit_sig, + const u32 lease_chan_max_msat, + const u16 lease_chan_max_ppt); /* Given a txid, find an inflight channel stub. Returns NULL if none found */ struct channel_inflight *channel_inflight_find(struct channel *channel, diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index 464ef2a5336c..cb655cf734c4 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -1112,7 +1112,11 @@ wallet_update_channel(struct lightningd *ld, struct amount_sat total_funding, struct amount_sat our_funding, u32 funding_feerate, - struct wally_psbt *psbt STEALS) + struct wally_psbt *psbt STEALS, + const u32 lease_expiry, + secp256k1_ecdsa_signature *lease_commit_sig STEALS, + const u32 lease_chan_max_msat, + const u16 lease_chan_max_ppt) { struct amount_msat our_msat; struct channel_inflight *inflight; @@ -1132,6 +1136,12 @@ wallet_update_channel(struct lightningd *ld, channel->our_msat = our_msat; channel->msat_to_us_min = our_msat; channel->msat_to_us_max = our_msat; + channel->lease_expiry = lease_expiry; + + tal_free(channel->lease_commit_sig); + channel->lease_commit_sig = tal_steal(channel, lease_commit_sig); + channel->lease_chan_max_msat = lease_chan_max_msat; + channel->lease_chan_max_ppt = lease_chan_max_ppt; channel_set_last_tx(channel, tal_steal(channel, remote_commit), @@ -1150,7 +1160,11 @@ wallet_update_channel(struct lightningd *ld, channel->our_funds, psbt, channel->last_tx, - channel->last_sig); + channel->last_sig, + channel->lease_expiry, + channel->lease_commit_sig, + channel->lease_chan_max_msat, + channel->lease_chan_max_ppt); wallet_inflight_add(ld->wallet, inflight); return inflight; @@ -1171,7 +1185,11 @@ wallet_commit_channel(struct lightningd *ld, u32 commitment_feerate, const u8 *our_upfront_shutdown_script, const u8 *remote_upfront_shutdown_script, - struct wally_psbt *psbt STEALS) + struct wally_psbt *psbt STEALS, + const u32 lease_expiry, + secp256k1_ecdsa_signature *lease_commit_sig STEALS, + const u32 lease_chan_max_msat, + const u16 lease_chan_max_ppt) { struct amount_msat our_msat; struct channel_inflight *inflight; @@ -1238,6 +1256,15 @@ wallet_commit_channel(struct lightningd *ld, * in theory, but it's only used for timing out. */ channel->first_blocknum = get_block_height(ld->topology); + /* Update lease info for channel */ + channel->lease_expiry = lease_expiry; + + tal_free(channel->lease_commit_sig); + channel->lease_commit_sig = tal_steal(channel, lease_commit_sig); + + channel->lease_chan_max_msat = lease_chan_max_msat; + channel->lease_chan_max_ppt = lease_chan_max_ppt; + /* Now we finally put it in the database. */ wallet_channel_insert(ld->wallet, channel); @@ -1250,7 +1277,11 @@ wallet_commit_channel(struct lightningd *ld, channel->our_funds, psbt, channel->last_tx, - channel->last_sig); + channel->last_sig, + channel->lease_expiry, + channel->lease_commit_sig, + channel->lease_chan_max_msat, + channel->lease_chan_max_ppt); wallet_inflight_add(ld->wallet, inflight); return inflight; @@ -2785,8 +2816,9 @@ static void handle_commit_received(struct subd *dualopend, struct bitcoin_tx *remote_commit; struct bitcoin_signature remote_commit_sig; struct bitcoin_txid funding_txid; - u16 funding_outnum; - u32 feerate_funding, feerate_commitment; + u16 funding_outnum, lease_chan_max_ppt; + u32 feerate_funding, feerate_commitment, lease_expiry, + lease_chan_max_msat; struct amount_sat total_funding, funding_ours; u8 *remote_upfront_shutdown_script, *local_upfront_shutdown_script; @@ -2796,6 +2828,7 @@ static void handle_commit_received(struct subd *dualopend, struct openchannel2_psbt_payload *payload; struct channel_inflight *inflight; struct command *cmd = oa->cmd; + secp256k1_ecdsa_signature *lease_commit_sig; if (!fromwire_dualopend_commit_rcvd(tmpctx, msg, &channel_info.their_config, @@ -2817,7 +2850,11 @@ static void handle_commit_received(struct subd *dualopend, &feerate_funding, &feerate_commitment, &local_upfront_shutdown_script, - &remote_upfront_shutdown_script)) { + &remote_upfront_shutdown_script, + &lease_expiry, + &lease_commit_sig, + &lease_chan_max_msat, + &lease_chan_max_ppt)) { channel_internal_error(channel, "Bad WIRE_DUALOPEND_COMMIT_RCVD: %s", tal_hex(msg, msg)); @@ -2858,7 +2895,11 @@ static void handle_commit_received(struct subd *dualopend, oa->our_upfront_shutdown_script : local_upfront_shutdown_script, remote_upfront_shutdown_script, - psbt))) { + psbt, + lease_expiry, + lease_commit_sig, + lease_chan_max_msat, + lease_chan_max_ppt))) { channel_internal_error(channel, "wallet_commit_channel failed" " (chan %s)", @@ -2887,7 +2928,11 @@ static void handle_commit_received(struct subd *dualopend, total_funding, funding_ours, feerate_funding, - psbt))) { + psbt, + lease_expiry, + lease_commit_sig, + lease_chan_max_msat, + lease_chan_max_ppt))) { channel_internal_error(channel, "wallet_update_channel failed" " (chan %s)", @@ -3247,7 +3292,11 @@ void peer_restart_dualopend(struct peer *peer, channel->remote_upfront_shutdown_script, inflight->remote_tx_sigs, channel->fee_states, - channel->channel_flags); + channel->channel_flags, + inflight->lease_expiry, + inflight->lease_commit_sig, + inflight->lease_chan_max_msat, + inflight->lease_chan_max_ppt); subd_send_msg(channel->owner, take(msg)); diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 394b64525cf4..b17060a8fad3 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -216,7 +216,8 @@ wallet_commit_channel(struct lightningd *ld, option_anchor_outputs, NUM_SIDES, /* closer not yet known */ uc->fc ? REASON_USER : REASON_REMOTE, - NULL); + NULL, + 0, NULL, 0, 0); /* No leases on v1s */ /* Now we finally put it in the database. */ wallet_channel_insert(ld->wallet, channel); diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 9d74abd01d8d..f7294b843136 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -1338,6 +1338,13 @@ static void update_channel_from_inflight(struct lightningd *ld, channel->funding = inflight->funding->total_funds; channel->our_funds = inflight->funding->our_funds; + /* Lease infos ! */ + channel->lease_expiry = inflight->lease_expiry; + channel->lease_commit_sig + = tal_steal(channel, inflight->lease_commit_sig); + channel->lease_chan_max_msat = inflight->lease_chan_max_msat; + channel->lease_chan_max_ppt = inflight->lease_chan_max_ppt; + /* Make a 'clone' of this tx */ psbt_copy = clone_psbt(channel, inflight->last_tx->psbt); channel_set_last_tx(channel, diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 759d0406b9c2..9b0a4da1a299 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -126,6 +126,15 @@ struct tx_state { /* If delay til the channel funds lease expires */ u32 lease_expiry; + + /* Lease's commit sig */ + secp256k1_ecdsa_signature *lease_commit_sig; + + /* Lease's commited chan max msat */ + u32 lease_chan_max_msat; + + /* Lease's commited chan max ppt */ + u16 lease_chan_max_ppt; }; static struct tx_state *new_tx_state(const tal_t *ctx) @@ -134,6 +143,11 @@ static struct tx_state *new_tx_state(const tal_t *ctx) tx_state->psbt = NULL; tx_state->remote_funding_sigs_rcvd = false; + tx_state->lease_expiry = 0; + tx_state->lease_commit_sig = NULL; + tx_state->lease_chan_max_msat = 0; + tx_state->lease_chan_max_ppt = 0; + for (size_t i = 0; i < NUM_TX_MSGS; i++) tx_state->tx_msg_count[i] = 0; @@ -535,6 +549,7 @@ static char *check_balances(const tal_t *ctx, struct state *state, struct tx_state *tx_state, struct wally_psbt *psbt, + struct amount_sat lease_fee, u32 feerate_per_kw_funding) { struct amount_sat initiator_inputs, initiator_outs, @@ -681,8 +696,18 @@ static char *check_balances(const tal_t *ctx, } } tot_output_amt = AMOUNT_SAT(0); + initiator_outs = tx_state->opener_funding; accepter_outs = tx_state->accepter_funding; + + /* The lease_fee has been added to the accepter_funding, + * but the opener_funding is responsible for covering it, + * so we do a little switcheroo here */ + if (!amount_sat_add(&initiator_outs, initiator_outs, lease_fee)) + return "overflow adding lease_fee to initiator's funding"; + if (!amount_sat_sub(&accepter_outs, accepter_outs, lease_fee)) + return "unable to subtract lease_fee from accepter's funding"; + for (size_t i = 0; i < psbt->num_outputs; i++) { struct amount_sat amt = psbt_output_get_amount(psbt, i); @@ -1668,6 +1693,7 @@ static void revert_channel_state(struct state *state) static u8 *accepter_commits(struct state *state, struct tx_state *tx_state, struct amount_sat total, + struct amount_sat lease_fee, char **err_reason) { struct wally_tx_output *direct_outputs[NUM_SIDES]; @@ -1702,6 +1728,7 @@ static u8 *accepter_commits(struct state *state, /* Check tx funds are sane */ error = check_balances(tmpctx, state, tx_state, tx_state->psbt, + lease_fee, tx_state->feerate_per_kw_funding); if (error) { *err_reason = tal_fmt(tmpctx, "Insufficiently funded" @@ -1869,7 +1896,11 @@ static u8 *accepter_commits(struct state *state, tx_state->feerate_per_kw_funding, state->feerate_per_kw_commitment, state->upfront_shutdown_script[LOCAL], - state->upfront_shutdown_script[REMOTE]); + state->upfront_shutdown_script[REMOTE], + tx_state->lease_expiry, + tx_state->lease_commit_sig, + tx_state->lease_chan_max_msat, + tx_state->lease_chan_max_ppt); wire_sync_write(REQ_FD, take(msg)); msg = wire_sync_read(tmpctx, REQ_FD); @@ -1886,17 +1917,19 @@ static u8 *accepter_commits(struct state *state, } static void accept_tlv_add_offer(struct tlv_accept_tlvs *a_tlv, + struct tx_state *tx_state, struct lease_rates *rates, struct pubkey funding_pubkey, u32 blockheight) { - secp256k1_ecdsa_signature ad_sig; u8 *msg; + u32 lease_expiry = blockheight + LEASE_RATE_DURATION; + tx_state->lease_commit_sig = tal(tx_state, secp256k1_ecdsa_signature); /* Go get the signature for this lease offer from HSMD */ msg = towire_hsmd_sign_option_will_fund_offer(NULL, &funding_pubkey, - blockheight, + lease_expiry, rates->channel_fee_max_base_msat, rates->channel_fee_max_proportional_thousandths); if (!wire_sync_write(HSM_FD, take(msg))) @@ -1904,7 +1937,8 @@ static void accept_tlv_add_offer(struct tlv_accept_tlvs *a_tlv, "Could not write to HSM: %s", strerror(errno)); msg = wire_sync_read(tmpctx, HSM_FD); - if (!fromwire_hsmd_sign_option_will_fund_offer_reply(msg, &ad_sig)) + if (!fromwire_hsmd_sign_option_will_fund_offer_reply(msg, + tx_state->lease_commit_sig)) status_failed(STATUS_FAIL_HSM_IO, "Bad sign_option_will_fund_offer_reply %s", tal_hex(tmpctx, msg)); @@ -1927,7 +1961,13 @@ static void accept_tlv_add_offer(struct tlv_accept_tlvs *a_tlv, */ a_tlv->will_fund = tal(a_tlv, struct tlv_accept_tlvs_will_fund); a_tlv->will_fund->lease_rates = *rates; - a_tlv->will_fund->signature = ad_sig; + a_tlv->will_fund->signature = *tx_state->lease_commit_sig; + + tx_state->lease_expiry = lease_expiry; + tx_state->lease_chan_max_msat + = rates->channel_fee_max_base_msat; + tx_state->lease_chan_max_ppt + = rates->channel_fee_max_proportional_thousandths; } static void accepter_start(struct state *state, const u8 *oc2_msg) @@ -1937,7 +1977,7 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) struct channel_id cid, full_cid; char *err_reason; u8 *msg; - struct amount_sat total, requested_amt; + struct amount_sat total, requested_amt, lease_fee; u32 lease_blockheight_start; enum dualopend_wire msg_type; struct tx_state *tx_state = state->tx_state; @@ -2164,9 +2204,10 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) * - MUST include a `will_fund` tlv */ if (open_tlv->request_funds && tx_state->rates) - accept_tlv_add_offer(a_tlv, tx_state->rates, + accept_tlv_add_offer(a_tlv, tx_state, tx_state->rates, state->our_funding_pubkey, - lease_blockheight_start + LEASE_RATE_DURATION); + lease_blockheight_start); + msg = towire_accept_channel2(tmpctx, &state->channel_id, tx_state->accepter_funding, @@ -2194,8 +2235,6 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) /* Add our fee to our amount now */ if (tx_state->rates) { - struct amount_sat lease_fee; - tx_state->lease_expiry = lease_blockheight_start + LEASE_RATE_DURATION; @@ -2230,8 +2269,10 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) &lease_fee)); return; } - } else + } else { tx_state->lease_expiry = 0; + lease_fee = AMOUNT_SAT(0); + } /* This is unused in this flow. We re-use * the wire method between accepter + opener, so we set it @@ -2241,7 +2282,8 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) if (!run_tx_interactive(state, tx_state, &tx_state->psbt, TX_ACCEPTER)) return; - msg = accepter_commits(state, tx_state, total, &err_reason); + msg = accepter_commits(state, tx_state, total, + lease_fee, &err_reason); if (!msg) { if (err_reason) negotiation_failed(state, "%s", err_reason); @@ -2278,6 +2320,7 @@ static void add_funding_output(struct tx_state *tx_state, static u8 *opener_commits(struct state *state, struct tx_state *tx_state, struct amount_sat total, + struct amount_sat lease_fee, char **err_reason) { struct channel_id cid; @@ -2311,6 +2354,7 @@ static u8 *opener_commits(struct state *state, error = check_balances(tmpctx, state, tx_state, tx_state->psbt, + lease_fee, tx_state->feerate_per_kw_funding); if (error) { *err_reason = tal_fmt(tmpctx, "Insufficiently funded funding " @@ -2505,7 +2549,11 @@ static u8 *opener_commits(struct state *state, tx_state->feerate_per_kw_funding, state->feerate_per_kw_commitment, state->upfront_shutdown_script[LOCAL], - state->upfront_shutdown_script[REMOTE]); + state->upfront_shutdown_script[REMOTE], + tx_state->lease_expiry, + tx_state->lease_commit_sig, + tx_state->lease_chan_max_msat, + tx_state->lease_chan_max_ppt); } @@ -2515,7 +2563,7 @@ static void opener_start(struct state *state, u8 *msg) struct tlv_accept_tlvs *a_tlv; struct channel_id cid; char *err_reason; - struct amount_sat total, requested_sats; + struct amount_sat total, requested_sats, lease_fee; u32 current_blockheight; bool dry_run; struct tx_state *tx_state = state->tx_state; @@ -2676,7 +2724,6 @@ static void opener_start(struct state *state, u8 *msg) if (open_tlv->request_funds && a_tlv->will_fund) { char *err_msg; struct lease_rates *rates = &a_tlv->will_fund->lease_rates; - struct amount_sat lease_fee; tx_state->lease_expiry = current_blockheight + LEASE_RATE_DURATION; @@ -2728,8 +2775,16 @@ static void opener_start(struct state *state, u8 *msg) &lease_fee)); return; } + + tx_state->lease_commit_sig + = tal_dup(tx_state, secp256k1_ecdsa_signature, + &a_tlv->will_fund->signature); + tx_state->lease_chan_max_msat + = rates->channel_fee_max_base_msat; + tx_state->lease_chan_max_ppt + = rates->channel_fee_max_proportional_thousandths; } else - tx_state->lease_expiry = 0; + lease_fee = AMOUNT_SAT(0); /* Check that total funding doesn't overflow */ if (!amount_sat_add(&total, tx_state->opener_funding, @@ -2794,7 +2849,7 @@ static void opener_start(struct state *state, u8 *msg) if (!run_tx_interactive(state, tx_state, &tx_state->psbt, TX_INITIATOR)) return; - msg = opener_commits(state, tx_state, total, &err_reason); + msg = opener_commits(state, tx_state, total, lease_fee, &err_reason); if (!msg) { if (err_reason) open_err_warn(state, "%s", err_reason); @@ -2916,9 +2971,12 @@ static void rbf_wrap_up(struct state *state, psbt_txid(NULL, tx_state->psbt, &tx_state->funding_txid, NULL); if (state->our_role == TX_ACCEPTER) - msg = accepter_commits(state, tx_state, total, &err_reason); + /* FIXME: lease fee rate !? */ + msg = accepter_commits(state, tx_state, total, + AMOUNT_SAT(0), &err_reason); else - msg = opener_commits(state, tx_state, total, &err_reason); + msg = opener_commits(state, tx_state, total, + AMOUNT_SAT(0), &err_reason); if (!msg) { if (err_reason) @@ -3739,7 +3797,11 @@ int main(int argc, char *argv[]) &state->upfront_shutdown_script[REMOTE], &state->tx_state->remote_funding_sigs_rcvd, &fee_states, - &state->channel_flags)) { + &state->channel_flags, + &state->tx_state->lease_expiry, + &state->tx_state->lease_commit_sig, + &state->tx_state->lease_chan_max_msat, + &state->tx_state->lease_chan_max_ppt)) { /*~ We only reconnect on channels that the * saved the the database (exchanged commitment sigs) */ diff --git a/openingd/dualopend_wire.csv b/openingd/dualopend_wire.csv index 558abc98198e..82d88173c064 100644 --- a/openingd/dualopend_wire.csv +++ b/openingd/dualopend_wire.csv @@ -66,6 +66,10 @@ msgdata,dualopend_reinit,remote_shutdown_scriptpubkey,u8,remote_shutdown_len msgdata,dualopend_reinit,remote_funding_sigs_received,bool, msgdata,dualopend_reinit,fee_states,fee_states, msgdata,dualopend_reinit,channel_flags,u8, +msgdata,dualopend_reinit,lease_expiry,u32, +msgdata,dualopend_reinit,lease_commit_sig,?secp256k1_ecdsa_signature, +msgdata,dualopend_reinit,lease_chan_max_msat,u32, +msgdata,dualopend_reinit,lease_chan_max_ppt,u16, # dualopend->master: they offered channel, should we continue? msgtype,dualopend_got_offer,7005 @@ -142,6 +146,10 @@ msgdata,dualopend_commit_rcvd,local_shutdown_len,u16, msgdata,dualopend_commit_rcvd,local_shutdown_scriptpubkey,u8,local_shutdown_len msgdata,dualopend_commit_rcvd,remote_shutdown_len,u16, msgdata,dualopend_commit_rcvd,remote_shutdown_scriptpubkey,u8,remote_shutdown_len +msgdata,dualopend_commit_rcvd,lease_expiry,u32, +msgdata,dualopend_commit_rcvd,lease_commit_sig,?secp256k1_ecdsa_signature, +msgdata,dualopend_commit_rcvd,lease_chan_max_msat,u32, +msgdata,dualopend_commit_rcvd,lease_chan_max_ppt,u16, # dualopend->master: peer updated the psbt msgtype,dualopend_psbt_changed,7107 diff --git a/openingd/dualopend_wiregen.c b/openingd/dualopend_wiregen.c index 2fa679a99917..5f94893b664e 100644 --- a/openingd/dualopend_wiregen.c +++ b/openingd/dualopend_wiregen.c @@ -152,7 +152,7 @@ bool fromwire_dualopend_init(const tal_t *ctx, const void *p, const struct chain /* WIRE: DUALOPEND_REINIT */ /* master-dualopend: peer has reconnected */ -u8 *towire_dualopend_reinit(const tal_t *ctx, const struct chainparams *chainparams, const struct feature_set *our_feature_set, const u8 *their_init_features, const struct channel_config *our_config, const struct channel_config *their_config, const struct channel_id *channel_id, u32 max_to_self_delay, struct amount_msat min_effective_htlc_capacity_msat, const struct per_peer_state *pps, const struct basepoints *our_basepoints, const struct pubkey *our_funding_pubkey, const struct pubkey *their_funding_pubkey, u32 minimum_depth, const struct bitcoin_txid *funding_txid, u16 funding_txout, u32 orignal_feerate_per_kw_funding, u32 most_recent_feerate_per_kw_funding, struct amount_sat funding_satoshi, struct amount_msat our_funding, const struct basepoints *their_basepoints, const struct pubkey *remote_per_commit, const struct wally_psbt *funding_psbt, enum side opener, bool local_funding_locked, bool remote_funding_locked, bool send_shutdown, bool remote_shutdown_received, const u8 *local_shutdown_scriptpubkey, const u8 *remote_shutdown_scriptpubkey, bool remote_funding_sigs_received, const struct fee_states *fee_states, u8 channel_flags) +u8 *towire_dualopend_reinit(const tal_t *ctx, const struct chainparams *chainparams, const struct feature_set *our_feature_set, const u8 *their_init_features, const struct channel_config *our_config, const struct channel_config *their_config, const struct channel_id *channel_id, u32 max_to_self_delay, struct amount_msat min_effective_htlc_capacity_msat, const struct per_peer_state *pps, const struct basepoints *our_basepoints, const struct pubkey *our_funding_pubkey, const struct pubkey *their_funding_pubkey, u32 minimum_depth, const struct bitcoin_txid *funding_txid, u16 funding_txout, u32 orignal_feerate_per_kw_funding, u32 most_recent_feerate_per_kw_funding, struct amount_sat funding_satoshi, struct amount_msat our_funding, const struct basepoints *their_basepoints, const struct pubkey *remote_per_commit, const struct wally_psbt *funding_psbt, enum side opener, bool local_funding_locked, bool remote_funding_locked, bool send_shutdown, bool remote_shutdown_received, const u8 *local_shutdown_scriptpubkey, const u8 *remote_shutdown_scriptpubkey, bool remote_funding_sigs_received, const struct fee_states *fee_states, u8 channel_flags, u32 lease_expiry, const secp256k1_ecdsa_signature *lease_commit_sig, u32 lease_chan_max_msat, u16 lease_chan_max_ppt) { u16 their_init_features_len = tal_count(their_init_features); u16 local_shutdown_len = tal_count(local_shutdown_scriptpubkey); @@ -195,10 +195,19 @@ u8 *towire_dualopend_reinit(const tal_t *ctx, const struct chainparams *chainpar towire_bool(&p, remote_funding_sigs_received); towire_fee_states(&p, fee_states); towire_u8(&p, channel_flags); + towire_u32(&p, lease_expiry); + if (!lease_commit_sig) + towire_bool(&p, false); + else { + towire_bool(&p, true); + towire_secp256k1_ecdsa_signature(&p, lease_commit_sig); + } + towire_u32(&p, lease_chan_max_msat); + towire_u16(&p, lease_chan_max_ppt); return memcheck(p, tal_count(p)); } -bool fromwire_dualopend_reinit(const tal_t *ctx, const void *p, const struct chainparams **chainparams, struct feature_set **our_feature_set, u8 **their_init_features, struct channel_config *our_config, struct channel_config *their_config, struct channel_id *channel_id, u32 *max_to_self_delay, struct amount_msat *min_effective_htlc_capacity_msat, struct per_peer_state **pps, struct basepoints *our_basepoints, struct pubkey *our_funding_pubkey, struct pubkey *their_funding_pubkey, u32 *minimum_depth, struct bitcoin_txid *funding_txid, u16 *funding_txout, u32 *orignal_feerate_per_kw_funding, u32 *most_recent_feerate_per_kw_funding, struct amount_sat *funding_satoshi, struct amount_msat *our_funding, struct basepoints *their_basepoints, struct pubkey *remote_per_commit, struct wally_psbt **funding_psbt, enum side *opener, bool *local_funding_locked, bool *remote_funding_locked, bool *send_shutdown, bool *remote_shutdown_received, u8 **local_shutdown_scriptpubkey, u8 **remote_shutdown_scriptpubkey, bool *remote_funding_sigs_received, struct fee_states **fee_states, u8 *channel_flags) +bool fromwire_dualopend_reinit(const tal_t *ctx, const void *p, const struct chainparams **chainparams, struct feature_set **our_feature_set, u8 **their_init_features, struct channel_config *our_config, struct channel_config *their_config, struct channel_id *channel_id, u32 *max_to_self_delay, struct amount_msat *min_effective_htlc_capacity_msat, struct per_peer_state **pps, struct basepoints *our_basepoints, struct pubkey *our_funding_pubkey, struct pubkey *their_funding_pubkey, u32 *minimum_depth, struct bitcoin_txid *funding_txid, u16 *funding_txout, u32 *orignal_feerate_per_kw_funding, u32 *most_recent_feerate_per_kw_funding, struct amount_sat *funding_satoshi, struct amount_msat *our_funding, struct basepoints *their_basepoints, struct pubkey *remote_per_commit, struct wally_psbt **funding_psbt, enum side *opener, bool *local_funding_locked, bool *remote_funding_locked, bool *send_shutdown, bool *remote_shutdown_received, u8 **local_shutdown_scriptpubkey, u8 **remote_shutdown_scriptpubkey, bool *remote_funding_sigs_received, struct fee_states **fee_states, u8 *channel_flags, u32 *lease_expiry, secp256k1_ecdsa_signature **lease_commit_sig, u32 *lease_chan_max_msat, u16 *lease_chan_max_ppt) { u16 their_init_features_len; u16 local_shutdown_len; @@ -250,6 +259,15 @@ bool fromwire_dualopend_reinit(const tal_t *ctx, const void *p, const struct cha *remote_funding_sigs_received = fromwire_bool(&cursor, &plen); *fee_states = fromwire_fee_states(ctx, &cursor, &plen); *channel_flags = fromwire_u8(&cursor, &plen); + *lease_expiry = fromwire_u32(&cursor, &plen); + if (!fromwire_bool(&cursor, &plen)) + *lease_commit_sig = NULL; + else { + *lease_commit_sig = tal(ctx, secp256k1_ecdsa_signature); + fromwire_secp256k1_ecdsa_signature(&cursor, &plen, *lease_commit_sig); + } + *lease_chan_max_msat = fromwire_u32(&cursor, &plen); + *lease_chan_max_ppt = fromwire_u16(&cursor, &plen); return cursor != NULL; } @@ -474,7 +492,7 @@ bool fromwire_dualopend_rbf_init(const tal_t *ctx, const void *p, struct amount_ /* WIRE: DUALOPEND_COMMIT_RCVD */ /* dualopend->master: ready to commit channel open to database and */ /* get some signatures for the funding_tx. */ -u8 *towire_dualopend_commit_rcvd(const tal_t *ctx, const struct channel_config *their_config, const struct bitcoin_tx *remote_first_commit, const struct penalty_base *pbase, const struct bitcoin_signature *first_commit_sig, const struct wally_psbt *psbt, const struct pubkey *revocation_basepoint, const struct pubkey *payment_basepoint, const struct pubkey *htlc_basepoint, const struct pubkey *delayed_payment_basepoint, const struct pubkey *their_per_commit_point, const struct pubkey *remote_fundingkey, const struct bitcoin_txid *funding_txid, u16 funding_txout, struct amount_sat funding_satoshis, struct amount_sat our_funding_sats, u8 channel_flags, u32 feerate_per_kw_funding, u32 feerate_per_kw_commitment, const u8 *local_shutdown_scriptpubkey, const u8 *remote_shutdown_scriptpubkey) +u8 *towire_dualopend_commit_rcvd(const tal_t *ctx, const struct channel_config *their_config, const struct bitcoin_tx *remote_first_commit, const struct penalty_base *pbase, const struct bitcoin_signature *first_commit_sig, const struct wally_psbt *psbt, const struct pubkey *revocation_basepoint, const struct pubkey *payment_basepoint, const struct pubkey *htlc_basepoint, const struct pubkey *delayed_payment_basepoint, const struct pubkey *their_per_commit_point, const struct pubkey *remote_fundingkey, const struct bitcoin_txid *funding_txid, u16 funding_txout, struct amount_sat funding_satoshis, struct amount_sat our_funding_sats, u8 channel_flags, u32 feerate_per_kw_funding, u32 feerate_per_kw_commitment, const u8 *local_shutdown_scriptpubkey, const u8 *remote_shutdown_scriptpubkey, u32 lease_expiry, const secp256k1_ecdsa_signature *lease_commit_sig, u32 lease_chan_max_msat, u16 lease_chan_max_ppt) { u16 local_shutdown_len = tal_count(local_shutdown_scriptpubkey); u16 remote_shutdown_len = tal_count(remote_shutdown_scriptpubkey); @@ -508,10 +526,19 @@ u8 *towire_dualopend_commit_rcvd(const tal_t *ctx, const struct channel_config * towire_u8_array(&p, local_shutdown_scriptpubkey, local_shutdown_len); towire_u16(&p, remote_shutdown_len); towire_u8_array(&p, remote_shutdown_scriptpubkey, remote_shutdown_len); + towire_u32(&p, lease_expiry); + if (!lease_commit_sig) + towire_bool(&p, false); + else { + towire_bool(&p, true); + towire_secp256k1_ecdsa_signature(&p, lease_commit_sig); + } + towire_u32(&p, lease_chan_max_msat); + towire_u16(&p, lease_chan_max_ppt); return memcheck(p, tal_count(p)); } -bool fromwire_dualopend_commit_rcvd(const tal_t *ctx, const void *p, struct channel_config *their_config, struct bitcoin_tx **remote_first_commit, struct penalty_base **pbase, struct bitcoin_signature *first_commit_sig, struct wally_psbt **psbt, struct pubkey *revocation_basepoint, struct pubkey *payment_basepoint, struct pubkey *htlc_basepoint, struct pubkey *delayed_payment_basepoint, struct pubkey *their_per_commit_point, struct pubkey *remote_fundingkey, struct bitcoin_txid *funding_txid, u16 *funding_txout, struct amount_sat *funding_satoshis, struct amount_sat *our_funding_sats, u8 *channel_flags, u32 *feerate_per_kw_funding, u32 *feerate_per_kw_commitment, u8 **local_shutdown_scriptpubkey, u8 **remote_shutdown_scriptpubkey) +bool fromwire_dualopend_commit_rcvd(const tal_t *ctx, const void *p, struct channel_config *their_config, struct bitcoin_tx **remote_first_commit, struct penalty_base **pbase, struct bitcoin_signature *first_commit_sig, struct wally_psbt **psbt, struct pubkey *revocation_basepoint, struct pubkey *payment_basepoint, struct pubkey *htlc_basepoint, struct pubkey *delayed_payment_basepoint, struct pubkey *their_per_commit_point, struct pubkey *remote_fundingkey, struct bitcoin_txid *funding_txid, u16 *funding_txout, struct amount_sat *funding_satoshis, struct amount_sat *our_funding_sats, u8 *channel_flags, u32 *feerate_per_kw_funding, u32 *feerate_per_kw_commitment, u8 **local_shutdown_scriptpubkey, u8 **remote_shutdown_scriptpubkey, u32 *lease_expiry, secp256k1_ecdsa_signature **lease_commit_sig, u32 *lease_chan_max_msat, u16 *lease_chan_max_ppt) { u16 local_shutdown_len; u16 remote_shutdown_len; @@ -552,6 +579,15 @@ bool fromwire_dualopend_commit_rcvd(const tal_t *ctx, const void *p, struct chan // 2nd case remote_shutdown_scriptpubkey *remote_shutdown_scriptpubkey = remote_shutdown_len ? tal_arr(ctx, u8, remote_shutdown_len) : NULL; fromwire_u8_array(&cursor, &plen, *remote_shutdown_scriptpubkey, remote_shutdown_len); + *lease_expiry = fromwire_u32(&cursor, &plen); + if (!fromwire_bool(&cursor, &plen)) + *lease_commit_sig = NULL; + else { + *lease_commit_sig = tal(ctx, secp256k1_ecdsa_signature); + fromwire_secp256k1_ecdsa_signature(&cursor, &plen, *lease_commit_sig); + } + *lease_chan_max_msat = fromwire_u32(&cursor, &plen); + *lease_chan_max_ppt = fromwire_u16(&cursor, &plen); return cursor != NULL; } @@ -1038,4 +1074,4 @@ bool fromwire_dualopend_validate_lease_reply(const tal_t *ctx, const void *p, wi } return cursor != NULL; } -// SHA256STAMP:ef969c3a15ae09102caa6f57f676a295e86f3fc1c01347c3fb9c6004bb6c7109 +// SHA256STAMP:5e2b2c6ce70bfc6f6e2f068e80a490ce36ebdfb50809c365914dd9ea8f4137a8 diff --git a/openingd/dualopend_wiregen.h b/openingd/dualopend_wiregen.h index 82ea606f1591..81aec61aecec 100644 --- a/openingd/dualopend_wiregen.h +++ b/openingd/dualopend_wiregen.h @@ -98,8 +98,8 @@ bool fromwire_dualopend_init(const tal_t *ctx, const void *p, const struct chain /* WIRE: DUALOPEND_REINIT */ /* master-dualopend: peer has reconnected */ -u8 *towire_dualopend_reinit(const tal_t *ctx, const struct chainparams *chainparams, const struct feature_set *our_feature_set, const u8 *their_init_features, const struct channel_config *our_config, const struct channel_config *their_config, const struct channel_id *channel_id, u32 max_to_self_delay, struct amount_msat min_effective_htlc_capacity_msat, const struct per_peer_state *pps, const struct basepoints *our_basepoints, const struct pubkey *our_funding_pubkey, const struct pubkey *their_funding_pubkey, u32 minimum_depth, const struct bitcoin_txid *funding_txid, u16 funding_txout, u32 orignal_feerate_per_kw_funding, u32 most_recent_feerate_per_kw_funding, struct amount_sat funding_satoshi, struct amount_msat our_funding, const struct basepoints *their_basepoints, const struct pubkey *remote_per_commit, const struct wally_psbt *funding_psbt, enum side opener, bool local_funding_locked, bool remote_funding_locked, bool send_shutdown, bool remote_shutdown_received, const u8 *local_shutdown_scriptpubkey, const u8 *remote_shutdown_scriptpubkey, bool remote_funding_sigs_received, const struct fee_states *fee_states, u8 channel_flags); -bool fromwire_dualopend_reinit(const tal_t *ctx, const void *p, const struct chainparams **chainparams, struct feature_set **our_feature_set, u8 **their_init_features, struct channel_config *our_config, struct channel_config *their_config, struct channel_id *channel_id, u32 *max_to_self_delay, struct amount_msat *min_effective_htlc_capacity_msat, struct per_peer_state **pps, struct basepoints *our_basepoints, struct pubkey *our_funding_pubkey, struct pubkey *their_funding_pubkey, u32 *minimum_depth, struct bitcoin_txid *funding_txid, u16 *funding_txout, u32 *orignal_feerate_per_kw_funding, u32 *most_recent_feerate_per_kw_funding, struct amount_sat *funding_satoshi, struct amount_msat *our_funding, struct basepoints *their_basepoints, struct pubkey *remote_per_commit, struct wally_psbt **funding_psbt, enum side *opener, bool *local_funding_locked, bool *remote_funding_locked, bool *send_shutdown, bool *remote_shutdown_received, u8 **local_shutdown_scriptpubkey, u8 **remote_shutdown_scriptpubkey, bool *remote_funding_sigs_received, struct fee_states **fee_states, u8 *channel_flags); +u8 *towire_dualopend_reinit(const tal_t *ctx, const struct chainparams *chainparams, const struct feature_set *our_feature_set, const u8 *their_init_features, const struct channel_config *our_config, const struct channel_config *their_config, const struct channel_id *channel_id, u32 max_to_self_delay, struct amount_msat min_effective_htlc_capacity_msat, const struct per_peer_state *pps, const struct basepoints *our_basepoints, const struct pubkey *our_funding_pubkey, const struct pubkey *their_funding_pubkey, u32 minimum_depth, const struct bitcoin_txid *funding_txid, u16 funding_txout, u32 orignal_feerate_per_kw_funding, u32 most_recent_feerate_per_kw_funding, struct amount_sat funding_satoshi, struct amount_msat our_funding, const struct basepoints *their_basepoints, const struct pubkey *remote_per_commit, const struct wally_psbt *funding_psbt, enum side opener, bool local_funding_locked, bool remote_funding_locked, bool send_shutdown, bool remote_shutdown_received, const u8 *local_shutdown_scriptpubkey, const u8 *remote_shutdown_scriptpubkey, bool remote_funding_sigs_received, const struct fee_states *fee_states, u8 channel_flags, u32 lease_expiry, const secp256k1_ecdsa_signature *lease_commit_sig, u32 lease_chan_max_msat, u16 lease_chan_max_ppt); +bool fromwire_dualopend_reinit(const tal_t *ctx, const void *p, const struct chainparams **chainparams, struct feature_set **our_feature_set, u8 **their_init_features, struct channel_config *our_config, struct channel_config *their_config, struct channel_id *channel_id, u32 *max_to_self_delay, struct amount_msat *min_effective_htlc_capacity_msat, struct per_peer_state **pps, struct basepoints *our_basepoints, struct pubkey *our_funding_pubkey, struct pubkey *their_funding_pubkey, u32 *minimum_depth, struct bitcoin_txid *funding_txid, u16 *funding_txout, u32 *orignal_feerate_per_kw_funding, u32 *most_recent_feerate_per_kw_funding, struct amount_sat *funding_satoshi, struct amount_msat *our_funding, struct basepoints *their_basepoints, struct pubkey *remote_per_commit, struct wally_psbt **funding_psbt, enum side *opener, bool *local_funding_locked, bool *remote_funding_locked, bool *send_shutdown, bool *remote_shutdown_received, u8 **local_shutdown_scriptpubkey, u8 **remote_shutdown_scriptpubkey, bool *remote_funding_sigs_received, struct fee_states **fee_states, u8 *channel_flags, u32 *lease_expiry, secp256k1_ecdsa_signature **lease_commit_sig, u32 *lease_chan_max_msat, u16 *lease_chan_max_ppt); /* WIRE: DUALOPEND_GOT_OFFER */ /* dualopend->master: they offered channel */ @@ -139,8 +139,8 @@ bool fromwire_dualopend_rbf_init(const tal_t *ctx, const void *p, struct amount_ /* WIRE: DUALOPEND_COMMIT_RCVD */ /* dualopend->master: ready to commit channel open to database and */ /* get some signatures for the funding_tx. */ -u8 *towire_dualopend_commit_rcvd(const tal_t *ctx, const struct channel_config *their_config, const struct bitcoin_tx *remote_first_commit, const struct penalty_base *pbase, const struct bitcoin_signature *first_commit_sig, const struct wally_psbt *psbt, const struct pubkey *revocation_basepoint, const struct pubkey *payment_basepoint, const struct pubkey *htlc_basepoint, const struct pubkey *delayed_payment_basepoint, const struct pubkey *their_per_commit_point, const struct pubkey *remote_fundingkey, const struct bitcoin_txid *funding_txid, u16 funding_txout, struct amount_sat funding_satoshis, struct amount_sat our_funding_sats, u8 channel_flags, u32 feerate_per_kw_funding, u32 feerate_per_kw_commitment, const u8 *local_shutdown_scriptpubkey, const u8 *remote_shutdown_scriptpubkey); -bool fromwire_dualopend_commit_rcvd(const tal_t *ctx, const void *p, struct channel_config *their_config, struct bitcoin_tx **remote_first_commit, struct penalty_base **pbase, struct bitcoin_signature *first_commit_sig, struct wally_psbt **psbt, struct pubkey *revocation_basepoint, struct pubkey *payment_basepoint, struct pubkey *htlc_basepoint, struct pubkey *delayed_payment_basepoint, struct pubkey *their_per_commit_point, struct pubkey *remote_fundingkey, struct bitcoin_txid *funding_txid, u16 *funding_txout, struct amount_sat *funding_satoshis, struct amount_sat *our_funding_sats, u8 *channel_flags, u32 *feerate_per_kw_funding, u32 *feerate_per_kw_commitment, u8 **local_shutdown_scriptpubkey, u8 **remote_shutdown_scriptpubkey); +u8 *towire_dualopend_commit_rcvd(const tal_t *ctx, const struct channel_config *their_config, const struct bitcoin_tx *remote_first_commit, const struct penalty_base *pbase, const struct bitcoin_signature *first_commit_sig, const struct wally_psbt *psbt, const struct pubkey *revocation_basepoint, const struct pubkey *payment_basepoint, const struct pubkey *htlc_basepoint, const struct pubkey *delayed_payment_basepoint, const struct pubkey *their_per_commit_point, const struct pubkey *remote_fundingkey, const struct bitcoin_txid *funding_txid, u16 funding_txout, struct amount_sat funding_satoshis, struct amount_sat our_funding_sats, u8 channel_flags, u32 feerate_per_kw_funding, u32 feerate_per_kw_commitment, const u8 *local_shutdown_scriptpubkey, const u8 *remote_shutdown_scriptpubkey, u32 lease_expiry, const secp256k1_ecdsa_signature *lease_commit_sig, u32 lease_chan_max_msat, u16 lease_chan_max_ppt); +bool fromwire_dualopend_commit_rcvd(const tal_t *ctx, const void *p, struct channel_config *their_config, struct bitcoin_tx **remote_first_commit, struct penalty_base **pbase, struct bitcoin_signature *first_commit_sig, struct wally_psbt **psbt, struct pubkey *revocation_basepoint, struct pubkey *payment_basepoint, struct pubkey *htlc_basepoint, struct pubkey *delayed_payment_basepoint, struct pubkey *their_per_commit_point, struct pubkey *remote_fundingkey, struct bitcoin_txid *funding_txid, u16 *funding_txout, struct amount_sat *funding_satoshis, struct amount_sat *our_funding_sats, u8 *channel_flags, u32 *feerate_per_kw_funding, u32 *feerate_per_kw_commitment, u8 **local_shutdown_scriptpubkey, u8 **remote_shutdown_scriptpubkey, u32 *lease_expiry, secp256k1_ecdsa_signature **lease_commit_sig, u32 *lease_chan_max_msat, u16 *lease_chan_max_ppt); /* WIRE: DUALOPEND_PSBT_CHANGED */ /* dualopend->master: peer updated the psbt */ @@ -237,4 +237,4 @@ bool fromwire_dualopend_validate_lease_reply(const tal_t *ctx, const void *p, wi #endif /* LIGHTNING_OPENINGD_DUALOPEND_WIREGEN_H */ -// SHA256STAMP:ef969c3a15ae09102caa6f57f676a295e86f3fc1c01347c3fb9c6004bb6c7109 +// SHA256STAMP:5e2b2c6ce70bfc6f6e2f068e80a490ce36ebdfb50809c365914dd9ea8f4137a8 diff --git a/wallet/db.c b/wallet/db.c index be0fc74d42ff..1eb917a9beec 100644 --- a/wallet/db.c +++ b/wallet/db.c @@ -728,6 +728,14 @@ static struct migration dbmigrations[] = { " local_static_remotekey_start = 9223372036854775807" " WHERE option_static_remotekey = 0"), NULL}, + {SQL("ALTER TABLE channel_funding_inflights ADD lease_commit_sig BLOB DEFAULT NULL"), NULL}, + {SQL("ALTER TABLE channel_funding_inflights ADD lease_chan_max_msat BIGINT DEFAULT NULL"), NULL}, + {SQL("ALTER TABLE channel_funding_inflights ADD lease_chan_max_ppt INTEGER DEFAULT NULL"), NULL}, + {SQL("ALTER TABLE channel_funding_inflights ADD lease_expiry INTEGER DEFAULT 0"), NULL}, + {SQL("ALTER TABLE channels ADD lease_commit_sig BLOB DEFAULT NULL"), NULL}, + {SQL("ALTER TABLE channels ADD lease_chan_max_msat INTEGER DEFAULT NULL"), NULL}, + {SQL("ALTER TABLE channels ADD lease_chan_max_ppt INTEGER DEFAULT NULL"), NULL}, + {SQL("ALTER TABLE channels ADD lease_expiry INTEGER DEFAULT 0"), NULL}, }; /* Leak tracking. */ diff --git a/wallet/db_postgres_sqlgen.c b/wallet/db_postgres_sqlgen.c index 8a3b70c5776d..fc1005c292d4 100644 --- a/wallet/db_postgres_sqlgen.c +++ b/wallet/db_postgres_sqlgen.c @@ -956,6 +956,54 @@ struct db_query db_postgres_queries[] = { .placeholders = 0, .readonly = false, }, + { + .name = "ALTER TABLE channel_funding_inflights ADD lease_commit_sig BLOB DEFAULT NULL", + .query = "ALTER TABLE channel_funding_inflights ADD lease_commit_sig BYTEA DEFAULT NULL", + .placeholders = 0, + .readonly = false, + }, + { + .name = "ALTER TABLE channel_funding_inflights ADD lease_chan_max_msat BIGINT DEFAULT NULL", + .query = "ALTER TABLE channel_funding_inflights ADD lease_chan_max_msat BIGINT DEFAULT NULL", + .placeholders = 0, + .readonly = false, + }, + { + .name = "ALTER TABLE channel_funding_inflights ADD lease_chan_max_ppt INTEGER DEFAULT NULL", + .query = "ALTER TABLE channel_funding_inflights ADD lease_chan_max_ppt INTEGER DEFAULT NULL", + .placeholders = 0, + .readonly = false, + }, + { + .name = "ALTER TABLE channel_funding_inflights ADD lease_expiry INTEGER DEFAULT 0", + .query = "ALTER TABLE channel_funding_inflights ADD lease_expiry INTEGER DEFAULT 0", + .placeholders = 0, + .readonly = false, + }, + { + .name = "ALTER TABLE channels ADD lease_commit_sig BLOB DEFAULT NULL", + .query = "ALTER TABLE channels ADD lease_commit_sig BYTEA DEFAULT NULL", + .placeholders = 0, + .readonly = false, + }, + { + .name = "ALTER TABLE channels ADD lease_chan_max_msat INTEGER DEFAULT NULL", + .query = "ALTER TABLE channels ADD lease_chan_max_msat INTEGER DEFAULT NULL", + .placeholders = 0, + .readonly = false, + }, + { + .name = "ALTER TABLE channels ADD lease_chan_max_ppt INTEGER DEFAULT NULL", + .query = "ALTER TABLE channels ADD lease_chan_max_ppt INTEGER DEFAULT NULL", + .placeholders = 0, + .readonly = false, + }, + { + .name = "ALTER TABLE channels ADD lease_expiry INTEGER DEFAULT 0", + .query = "ALTER TABLE channels ADD lease_expiry INTEGER DEFAULT 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", @@ -1311,8 +1359,8 @@ struct db_query db_postgres_queries[] = { .readonly = false, }, { - .name = "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", - .query = "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 = $1 ORDER BY funding_feerate", + .name = "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, lease_expiry, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt FROM channel_funding_inflights WHERE channel_id = ? ORDER BY funding_feerate", + .query = "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, lease_expiry, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt FROM channel_funding_inflights WHERE channel_id = $1 ORDER BY funding_feerate", .placeholders = 1, .readonly = true, }, @@ -1323,8 +1371,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, 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;", + .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, lease_expiry, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt 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, lease_expiry, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt FROM channels WHERE state != $1;", .placeholders = 1, .readonly = true, }, @@ -1389,9 +1437,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=?, 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, + .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=?, lease_expiry=?, lease_commit_sig=?, lease_chan_max_msat=?, lease_chan_max_ppt=? 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, lease_expiry=$39, lease_commit_sig=$40, lease_chan_max_msat=$41, lease_chan_max_ppt=$42 WHERE id=$43", + .placeholders = 43, .readonly = false, }, { @@ -1918,10 +1966,10 @@ struct db_query db_postgres_queries[] = { }, }; -#define DB_POSTGRES_QUERY_COUNT 318 +#define DB_POSTGRES_QUERY_COUNT 326 #endif /* HAVE_POSTGRES */ #endif /* LIGHTNINGD_WALLET_GEN_DB_POSTGRES */ -// SHA256STAMP:1379bcdee314439910fc6b238f7ec986536543c53933883ffd1b750dfc34f9b9 +// SHA256STAMP:06e51ede39e83d9416af098b0d38f8c778109558d3b9483cfc946554940dfab2 diff --git a/wallet/db_sqlite3_sqlgen.c b/wallet/db_sqlite3_sqlgen.c index 98ed0bf0c4b6..83f12d32f56c 100644 --- a/wallet/db_sqlite3_sqlgen.c +++ b/wallet/db_sqlite3_sqlgen.c @@ -956,6 +956,54 @@ struct db_query db_sqlite3_queries[] = { .placeholders = 0, .readonly = false, }, + { + .name = "ALTER TABLE channel_funding_inflights ADD lease_commit_sig BLOB DEFAULT NULL", + .query = "ALTER TABLE channel_funding_inflights ADD lease_commit_sig BLOB DEFAULT NULL", + .placeholders = 0, + .readonly = false, + }, + { + .name = "ALTER TABLE channel_funding_inflights ADD lease_chan_max_msat BIGINT DEFAULT NULL", + .query = "ALTER TABLE channel_funding_inflights ADD lease_chan_max_msat INTEGER DEFAULT NULL", + .placeholders = 0, + .readonly = false, + }, + { + .name = "ALTER TABLE channel_funding_inflights ADD lease_chan_max_ppt INTEGER DEFAULT NULL", + .query = "ALTER TABLE channel_funding_inflights ADD lease_chan_max_ppt INTEGER DEFAULT NULL", + .placeholders = 0, + .readonly = false, + }, + { + .name = "ALTER TABLE channel_funding_inflights ADD lease_expiry INTEGER DEFAULT 0", + .query = "ALTER TABLE channel_funding_inflights ADD lease_expiry INTEGER DEFAULT 0", + .placeholders = 0, + .readonly = false, + }, + { + .name = "ALTER TABLE channels ADD lease_commit_sig BLOB DEFAULT NULL", + .query = "ALTER TABLE channels ADD lease_commit_sig BLOB DEFAULT NULL", + .placeholders = 0, + .readonly = false, + }, + { + .name = "ALTER TABLE channels ADD lease_chan_max_msat INTEGER DEFAULT NULL", + .query = "ALTER TABLE channels ADD lease_chan_max_msat INTEGER DEFAULT NULL", + .placeholders = 0, + .readonly = false, + }, + { + .name = "ALTER TABLE channels ADD lease_chan_max_ppt INTEGER DEFAULT NULL", + .query = "ALTER TABLE channels ADD lease_chan_max_ppt INTEGER DEFAULT NULL", + .placeholders = 0, + .readonly = false, + }, + { + .name = "ALTER TABLE channels ADD lease_expiry INTEGER DEFAULT 0", + .query = "ALTER TABLE channels ADD lease_expiry INTEGER DEFAULT 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 = ?", @@ -1311,8 +1359,8 @@ struct db_query db_sqlite3_queries[] = { .readonly = false, }, { - .name = "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", - .query = "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", + .name = "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, lease_expiry, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt FROM channel_funding_inflights WHERE channel_id = ? ORDER BY funding_feerate", + .query = "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, lease_expiry, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt FROM channel_funding_inflights WHERE channel_id = ? ORDER BY funding_feerate", .placeholders = 1, .readonly = true, }, @@ -1323,8 +1371,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, 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 != ?;", + .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, lease_expiry, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt 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, lease_expiry, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt FROM channels WHERE state != ?;", .placeholders = 1, .readonly = true, }, @@ -1389,9 +1437,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=?, 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, + .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=?, lease_expiry=?, lease_commit_sig=?, lease_chan_max_msat=?, lease_chan_max_ppt=? 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=?, lease_expiry=?, lease_commit_sig=?, lease_chan_max_msat=?, lease_chan_max_ppt=? WHERE id=?", + .placeholders = 43, .readonly = false, }, { @@ -1918,10 +1966,10 @@ struct db_query db_sqlite3_queries[] = { }, }; -#define DB_SQLITE3_QUERY_COUNT 318 +#define DB_SQLITE3_QUERY_COUNT 326 #endif /* HAVE_SQLITE3 */ #endif /* LIGHTNINGD_WALLET_GEN_DB_SQLITE3 */ -// SHA256STAMP:1379bcdee314439910fc6b238f7ec986536543c53933883ffd1b750dfc34f9b9 +// SHA256STAMP:06e51ede39e83d9416af098b0d38f8c778109558d3b9483cfc946554940dfab2 diff --git a/wallet/statements_gettextgen.po b/wallet/statements_gettextgen.po index 27896c8b6d17..74814b4738be 100644 --- a/wallet/statements_gettextgen.po +++ b/wallet/statements_gettextgen.po @@ -630,83 +630,115 @@ msgstr "" msgid "UPDATE channels SET remote_static_remotekey_start = 9223372036854775807, local_static_remotekey_start = 9223372036854775807 WHERE option_static_remotekey = 0" msgstr "" -#: wallet/db.c:957 +#: wallet/db.c:731 +msgid "ALTER TABLE channel_funding_inflights ADD lease_commit_sig BLOB DEFAULT NULL" +msgstr "" + +#: wallet/db.c:732 +msgid "ALTER TABLE channel_funding_inflights ADD lease_chan_max_msat BIGINT DEFAULT NULL" +msgstr "" + +#: wallet/db.c:733 +msgid "ALTER TABLE channel_funding_inflights ADD lease_chan_max_ppt INTEGER DEFAULT NULL" +msgstr "" + +#: wallet/db.c:734 +msgid "ALTER TABLE channel_funding_inflights ADD lease_expiry INTEGER DEFAULT 0" +msgstr "" + +#: wallet/db.c:735 +msgid "ALTER TABLE channels ADD lease_commit_sig BLOB DEFAULT NULL" +msgstr "" + +#: wallet/db.c:736 +msgid "ALTER TABLE channels ADD lease_chan_max_msat INTEGER DEFAULT NULL" +msgstr "" + +#: wallet/db.c:737 +msgid "ALTER TABLE channels ADD lease_chan_max_ppt INTEGER DEFAULT NULL" +msgstr "" + +#: wallet/db.c:738 +msgid "ALTER TABLE channels ADD lease_expiry INTEGER DEFAULT 0" +msgstr "" + +#: wallet/db.c:965 msgid "UPDATE vars SET intval = intval + 1 WHERE name = 'data_version' AND intval = ?" msgstr "" -#: wallet/db.c:1057 +#: wallet/db.c:1065 msgid "SELECT version FROM version LIMIT 1" msgstr "" -#: wallet/db.c:1119 +#: wallet/db.c:1127 msgid "UPDATE version SET version=?;" msgstr "" -#: wallet/db.c:1127 +#: wallet/db.c:1135 msgid "INSERT INTO db_upgrades VALUES (?, ?);" msgstr "" -#: wallet/db.c:1139 +#: wallet/db.c:1147 msgid "SELECT intval FROM vars WHERE name = 'data_version'" msgstr "" -#: wallet/db.c:1166 +#: wallet/db.c:1174 msgid "SELECT intval FROM vars WHERE name= ? LIMIT 1" msgstr "" -#: wallet/db.c:1182 +#: wallet/db.c:1190 msgid "UPDATE vars SET intval=? WHERE name=?;" msgstr "" -#: wallet/db.c:1191 +#: wallet/db.c:1199 msgid "INSERT INTO vars (name, intval) VALUES (?, ?);" msgstr "" -#: wallet/db.c:1205 +#: wallet/db.c:1213 msgid "UPDATE channels SET feerate_base = ?, feerate_ppm = ?;" msgstr "" -#: wallet/db.c:1226 +#: wallet/db.c:1234 msgid "UPDATE channels SET our_funding_satoshi = funding_satoshi WHERE funder = 0;" msgstr "" -#: wallet/db.c:1242 +#: wallet/db.c:1250 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:1304 +#: wallet/db.c:1312 msgid "UPDATE outputs SET scriptpubkey = ? WHERE prev_out_tx = ? AND prev_out_index = ?" msgstr "" -#: wallet/db.c:1329 +#: wallet/db.c:1337 msgid "SELECT id, funding_tx_id, funding_tx_outnum FROM channels;" msgstr "" -#: wallet/db.c:1348 +#: wallet/db.c:1356 msgid "UPDATE channels SET full_channel_id = ? WHERE id = ?;" msgstr "" -#: wallet/db.c:1369 +#: wallet/db.c:1377 msgid "SELECT channels.id, peers.node_id FROM channels JOIN peers ON (peers.id = channels.peer_id)" msgstr "" -#: wallet/db.c:1402 +#: wallet/db.c:1410 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:1428 +#: wallet/db.c:1436 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:1495 +#: wallet/db.c:1503 msgid "UPDATE channel_funding_inflights SET last_tx = ? WHERE channel_id = ? AND funding_tx_id = ?;" msgstr "" -#: wallet/db.c:1519 +#: wallet/db.c:1527 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:1586 +#: wallet/db.c:1594 msgid "UPDATE channels SET last_tx = ? WHERE id = ?;" msgstr "" @@ -866,391 +898,391 @@ msgstr "" msgid "DELETE FROM channel_funding_inflights WHERE channel_id = ?" msgstr "" -#: wallet/wallet.c:1079 -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" +#: wallet/wallet.c:1098 +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, lease_expiry, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt FROM channel_funding_inflights WHERE channel_id = ? ORDER BY funding_feerate" msgstr "" -#: wallet/wallet.c:1309 +#: wallet/wallet.c:1350 msgid "SELECT id FROM channels ORDER BY id DESC LIMIT 1;" msgstr "" -#: 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 != ?;" +#: wallet/wallet.c:1367 +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, lease_expiry, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt FROM channels WHERE state != ?;" msgstr "" -#: wallet/wallet.c:1434 +#: wallet/wallet.c:1479 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:1440 +#: wallet/wallet.c:1485 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:1446 +#: wallet/wallet.c:1491 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:1452 +#: wallet/wallet.c:1497 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:1497 +#: wallet/wallet.c:1542 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:1526 +#: wallet/wallet.c:1571 msgid "SELECT MIN(height), MAX(height) FROM blocks;" msgstr "" -#: wallet/wallet.c:1548 +#: wallet/wallet.c:1593 msgid "INSERT INTO channel_configs DEFAULT VALUES;" msgstr "" -#: wallet/wallet.c:1560 +#: wallet/wallet.c:1605 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:1584 +#: wallet/wallet.c:1629 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:1618 +#: wallet/wallet.c:1663 msgid "UPDATE channels SET remote_ann_node_sig=?, remote_ann_bitcoin_sig=? WHERE id=?" msgstr "" -#: 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=?" +#: wallet/wallet.c:1682 +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=?, lease_expiry=?, lease_commit_sig=?, lease_chan_max_msat=?, lease_chan_max_ppt=? WHERE id=?" msgstr "" -#: wallet/wallet.c:1731 +#: wallet/wallet.c:1791 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:1758 +#: wallet/wallet.c:1818 msgid "DELETE FROM channel_feerates WHERE channel_id=?" msgstr "" -#: wallet/wallet.c:1768 +#: wallet/wallet.c:1828 msgid "INSERT INTO channel_feerates VALUES(?, ?, ?)" msgstr "" -#: wallet/wallet.c:1785 +#: wallet/wallet.c:1845 msgid "UPDATE channels SET last_sent_commit=? WHERE id=?" msgstr "" -#: wallet/wallet.c:1808 +#: wallet/wallet.c:1868 msgid "INSERT INTO channel_state_changes ( channel_id, timestamp, old_state, new_state, cause, message) VALUES (?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:1836 +#: wallet/wallet.c:1896 msgid "SELECT timestamp, old_state, new_state, cause, message FROM channel_state_changes WHERE channel_id = ? ORDER BY timestamp ASC;" msgstr "" -#: wallet/wallet.c:1865 +#: wallet/wallet.c:1925 msgid "SELECT id FROM peers WHERE node_id = ?" msgstr "" -#: wallet/wallet.c:1877 +#: wallet/wallet.c:1937 msgid "UPDATE peers SET address = ? WHERE id = ?" msgstr "" -#: wallet/wallet.c:1886 +#: wallet/wallet.c:1946 msgid "INSERT INTO peers (node_id, address) VALUES (?, ?);" msgstr "" -#: wallet/wallet.c:1907 +#: wallet/wallet.c:1967 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:1948 +#: wallet/wallet.c:2008 msgid "DELETE FROM channel_htlcs WHERE channel_id=?" msgstr "" -#: wallet/wallet.c:1954 +#: wallet/wallet.c:2014 msgid "DELETE FROM htlc_sigs WHERE channelid=?" msgstr "" -#: wallet/wallet.c:1960 +#: wallet/wallet.c:2020 msgid "DELETE FROM channeltxs WHERE channel_id=?" msgstr "" -#: wallet/wallet.c:1967 +#: wallet/wallet.c:2027 msgid "DELETE FROM channel_funding_inflights WHERE channel_id=?" msgstr "" -#: wallet/wallet.c:1973 +#: wallet/wallet.c:2033 msgid "DELETE FROM shachains WHERE id IN ( SELECT shachain_remote_id FROM channels WHERE channels.id=?)" msgstr "" -#: wallet/wallet.c:1983 +#: wallet/wallet.c:2043 msgid "UPDATE channels SET state=?, peer_id=? WHERE channels.id=?" msgstr "" -#: wallet/wallet.c:1997 +#: wallet/wallet.c:2057 msgid "SELECT * FROM channels WHERE peer_id = ?;" msgstr "" -#: wallet/wallet.c:2005 +#: wallet/wallet.c:2065 msgid "DELETE FROM peers WHERE id=?" msgstr "" -#: wallet/wallet.c:2016 +#: wallet/wallet.c:2076 msgid "UPDATE outputs SET confirmation_height = ? WHERE prev_out_tx = ?" msgstr "" -#: wallet/wallet.c:2119 +#: wallet/wallet.c:2179 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:2172 +#: wallet/wallet.c:2232 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:2233 +#: wallet/wallet.c:2293 msgid "UPDATE channel_htlcs SET hstate=?, payment_key=?, malformed_onion=?, failuremsg=?, localfailmsg=?, we_filled=? WHERE id=?" msgstr "" -#: wallet/wallet.c:2450 +#: wallet/wallet.c:2510 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:2497 +#: wallet/wallet.c:2557 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:2628 +#: wallet/wallet.c:2688 msgid "SELECT channel_id, direction, cltv_expiry, channel_htlc_id, payment_hash FROM channel_htlcs WHERE channel_id = ?;" msgstr "" -#: wallet/wallet.c:2662 +#: wallet/wallet.c:2722 msgid "DELETE FROM channel_htlcs WHERE direction = ? AND origin_htlc = ? AND payment_hash = ? AND partid = ?;" msgstr "" -#: wallet/wallet.c:2715 +#: wallet/wallet.c:2775 msgid "SELECT status FROM payments WHERE payment_hash=? AND partid = ?;" msgstr "" -#: wallet/wallet.c:2733 +#: wallet/wallet.c:2793 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:2822 +#: wallet/wallet.c:2882 msgid "DELETE FROM payments WHERE payment_hash = ? AND partid = ?" msgstr "" -#: wallet/wallet.c:2836 +#: wallet/wallet.c:2896 msgid "DELETE FROM payments WHERE payment_hash = ?" msgstr "" -#: wallet/wallet.c:2937 +#: wallet/wallet.c:2997 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:2987 +#: wallet/wallet.c:3047 msgid "UPDATE payments SET status=? WHERE payment_hash=? AND partid=?" msgstr "" -#: wallet/wallet.c:2997 +#: wallet/wallet.c:3057 msgid "UPDATE payments SET payment_preimage=? WHERE payment_hash=? AND partid=?" msgstr "" -#: wallet/wallet.c:3007 +#: wallet/wallet.c:3067 msgid "UPDATE payments SET path_secrets = NULL , route_nodes = NULL , route_channels = NULL WHERE payment_hash = ? AND partid = ?;" msgstr "" -#: wallet/wallet.c:3039 +#: wallet/wallet.c:3099 msgid "SELECT failonionreply, faildestperm, failindex, failcode, failnode, failchannel, failupdate, faildetail, faildirection FROM payments WHERE payment_hash=? AND partid=?;" msgstr "" -#: wallet/wallet.c:3106 +#: wallet/wallet.c:3166 msgid "UPDATE payments SET failonionreply=? , faildestperm=? , failindex=? , failcode=? , failnode=? , failchannel=? , failupdate=? , faildetail=? , faildirection=? WHERE payment_hash=? AND partid=?;" msgstr "" -#: wallet/wallet.c:3165 +#: wallet/wallet.c:3225 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:3188 +#: wallet/wallet.c:3248 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:3239 +#: wallet/wallet.c:3299 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:3284 +#: wallet/wallet.c:3344 msgid "DELETE FROM htlc_sigs WHERE channelid = ?" msgstr "" -#: wallet/wallet.c:3291 +#: wallet/wallet.c:3351 msgid "INSERT INTO htlc_sigs (channelid, signature) VALUES (?, ?)" msgstr "" -#: wallet/wallet.c:3303 +#: wallet/wallet.c:3363 msgid "SELECT blobval FROM vars WHERE name='genesis_hash'" msgstr "" -#: wallet/wallet.c:3327 +#: wallet/wallet.c:3387 msgid "INSERT INTO vars (name, blobval) VALUES ('genesis_hash', ?);" msgstr "" -#: wallet/wallet.c:3345 +#: wallet/wallet.c:3405 msgid "SELECT txid, outnum FROM utxoset WHERE spendheight < ?" msgstr "" -#: wallet/wallet.c:3357 +#: wallet/wallet.c:3417 msgid "DELETE FROM utxoset WHERE spendheight < ?" msgstr "" -#: wallet/wallet.c:3365 wallet/wallet.c:3479 +#: wallet/wallet.c:3425 wallet/wallet.c:3539 msgid "INSERT INTO blocks (height, hash, prev_hash) VALUES (?, ?, ?);" msgstr "" -#: wallet/wallet.c:3384 +#: wallet/wallet.c:3444 msgid "DELETE FROM blocks WHERE hash = ?" msgstr "" -#: wallet/wallet.c:3390 +#: wallet/wallet.c:3450 msgid "SELECT * FROM blocks WHERE height >= ?;" msgstr "" -#: wallet/wallet.c:3399 +#: wallet/wallet.c:3459 msgid "DELETE FROM blocks WHERE height > ?" msgstr "" -#: wallet/wallet.c:3411 +#: wallet/wallet.c:3471 msgid "UPDATE outputs SET spend_height = ?, status = ? WHERE prev_out_tx = ? AND prev_out_index = ?" msgstr "" -#: wallet/wallet.c:3429 +#: wallet/wallet.c:3489 msgid "UPDATE utxoset SET spendheight = ? WHERE txid = ? AND outnum = ?" msgstr "" -#: wallet/wallet.c:3452 wallet/wallet.c:3490 +#: wallet/wallet.c:3512 wallet/wallet.c:3550 msgid "INSERT INTO utxoset ( txid, outnum, blockheight, spendheight, txindex, scriptpubkey, satoshis) VALUES(?, ?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:3516 +#: wallet/wallet.c:3576 msgid "SELECT height FROM blocks WHERE height = ?" msgstr "" -#: wallet/wallet.c:3529 +#: wallet/wallet.c:3589 msgid "SELECT txid, spendheight, scriptpubkey, satoshis FROM utxoset WHERE blockheight = ? AND txindex = ? AND outnum = ? AND spendheight IS NULL" msgstr "" -#: wallet/wallet.c:3571 +#: wallet/wallet.c:3631 msgid "SELECT blockheight, txindex, outnum FROM utxoset WHERE spendheight = ?" msgstr "" -#: wallet/wallet.c:3602 wallet/wallet.c:3762 +#: wallet/wallet.c:3662 wallet/wallet.c:3822 msgid "SELECT blockheight FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3612 +#: wallet/wallet.c:3672 msgid "INSERT INTO transactions ( id, blockheight, txindex, rawtx) VALUES (?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:3633 +#: wallet/wallet.c:3693 msgid "UPDATE transactions SET blockheight = ?, txindex = ? WHERE id = ?" msgstr "" -#: wallet/wallet.c:3650 +#: wallet/wallet.c:3710 msgid "INSERT INTO transaction_annotations (txid, idx, location, type, channel) VALUES (?, ?, ?, ?, ?) ON CONFLICT(txid,idx) DO NOTHING;" msgstr "" -#: wallet/wallet.c:3682 +#: wallet/wallet.c:3742 msgid "SELECT type, channel_id FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3698 +#: wallet/wallet.c:3758 msgid "UPDATE transactions SET type = ?, channel_id = ? WHERE id = ?" msgstr "" -#: wallet/wallet.c:3717 +#: wallet/wallet.c:3777 msgid "SELECT type FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3740 +#: wallet/wallet.c:3800 msgid "SELECT rawtx FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3786 +#: wallet/wallet.c:3846 msgid "SELECT blockheight, txindex FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3814 +#: wallet/wallet.c:3874 msgid "SELECT id FROM transactions WHERE blockheight=?" msgstr "" -#: wallet/wallet.c:3833 +#: wallet/wallet.c:3893 msgid "INSERT INTO channeltxs ( channel_id, type, transaction_id, input_num, blockheight) VALUES (?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:3857 +#: wallet/wallet.c:3917 msgid "SELECT DISTINCT(channel_id) FROM channeltxs WHERE type = ?;" msgstr "" -#: wallet/wallet.c:3878 +#: wallet/wallet.c:3938 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:3923 +#: wallet/wallet.c:3983 msgid "UPDATE forwarded_payments SET in_msatoshi=?, out_msatoshi=?, state=?, resolved_time=?, failcode=? WHERE in_htlc_id=?" msgstr "" -#: wallet/wallet.c:3981 +#: wallet/wallet.c:4041 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:4040 +#: wallet/wallet.c:4100 msgid "SELECT CAST(COALESCE(SUM(in_msatoshi - out_msatoshi), 0) AS BIGINT)FROM forwarded_payments WHERE state = ?;" msgstr "" -#: wallet/wallet.c:4089 +#: wallet/wallet.c:4149 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:4211 +#: wallet/wallet.c:4271 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:4305 +#: wallet/wallet.c:4365 msgid "INSERT INTO penalty_bases ( channel_id, commitnum, txid, outnum, amount) VALUES (?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:4330 +#: wallet/wallet.c:4390 msgid "SELECT commitnum, txid, outnum, amount FROM penalty_bases WHERE channel_id = ?" msgstr "" -#: wallet/wallet.c:4354 +#: wallet/wallet.c:4414 msgid "DELETE FROM penalty_bases WHERE channel_id = ? AND commitnum = ?" msgstr "" -#: wallet/wallet.c:4372 +#: wallet/wallet.c:4432 msgid "SELECT 1 FROM offers WHERE offer_id = ?;" msgstr "" -#: wallet/wallet.c:4385 +#: wallet/wallet.c:4445 msgid "INSERT INTO offers ( offer_id, bolt12, label, status) VALUES (?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:4412 +#: wallet/wallet.c:4472 msgid "SELECT bolt12, label, status FROM offers WHERE offer_id = ?;" msgstr "" -#: wallet/wallet.c:4440 +#: wallet/wallet.c:4500 msgid "SELECT offer_id FROM offers;" msgstr "" -#: wallet/wallet.c:4466 +#: wallet/wallet.c:4526 msgid "UPDATE offers SET status=? WHERE offer_id = ?;" msgstr "" -#: wallet/wallet.c:4477 +#: wallet/wallet.c:4537 msgid "UPDATE invoices SET state=? WHERE state=? AND local_offer_id = ?;" msgstr "" -#: wallet/wallet.c:4505 +#: wallet/wallet.c:4565 msgid "SELECT status FROM offers WHERE offer_id = ?;" msgstr "" @@ -1266,7 +1298,7 @@ msgstr "" msgid "SELECT COUNT(1) FROM channel_funding_inflights WHERE channel_id = ?;" msgstr "" -#: wallet/test/run-wallet.c:1649 +#: wallet/test/run-wallet.c:1653 msgid "INSERT INTO channels (id) VALUES (1);" msgstr "" -# SHA256STAMP:51de0bd1efd4b12ec550d3faf934a32f745018a46e61b50cc242c2d5bae09470 +# SHA256STAMP:916e655abfda9823c699c33992127a55f070317c2f7f89be918dc55a1d2e685e diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index ede16ddd6795..f8f2672fc68d 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -1541,7 +1541,9 @@ static bool test_channel_inflight_crud(struct lightningd *ld, const tal_t *ctx) &pk, NULL, 1000, 100, NULL, 0, 0, true, - LOCAL, REASON_UNKNOWN, NULL); + LOCAL, REASON_UNKNOWN, NULL, + 100, NULL, + 7777, 22); db_begin_transaction(w->db); CHECK(!wallet_err); wallet_channel_insert(w, chan); @@ -1557,7 +1559,8 @@ static bool test_channel_inflight_crud(struct lightningd *ld, const tal_t *ctx) our_sats, funding_psbt, last_tx, - sig); + sig, + 1, NULL, 2, 4); /* do inflights get correctly added to the channel? */ wallet_inflight_add(w, inflight); @@ -1578,7 +1581,8 @@ static bool test_channel_inflight_crud(struct lightningd *ld, const tal_t *ctx) our_sats, funding_psbt, last_tx, - sig); + sig, + 1, NULL, 2, 4); wallet_inflight_add(w, inflight); CHECK_MSG(c2 = wallet_channel_load(w, chan->dbid), tal_fmt(w, "Load from DB")); diff --git a/wallet/wallet.c b/wallet/wallet.c index d53652fece4c..7be2547f2fd4 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -1048,6 +1048,10 @@ wallet_stmt2inflight(struct wallet *w, struct db_stmt *stmt, struct bitcoin_signature last_sig; struct channel_inflight *inflight; + secp256k1_ecdsa_signature *lease_commit_sig; + u32 lease_chan_max_msat; + u16 lease_chan_max_ppt; + db_column_txid(stmt, 0, &funding_txid); db_column_amount_sat(stmt, 3, &funding_sat); db_column_amount_sat(stmt, 4, &our_funding_sat); @@ -1056,6 +1060,17 @@ wallet_stmt2inflight(struct wallet *w, struct db_stmt *stmt, last_sig.sighash_type = SIGHASH_ALL; + if (!db_column_is_null(stmt, 10)) { + lease_commit_sig = tal(tmpctx, secp256k1_ecdsa_signature); + db_column_signature(stmt, 10, lease_commit_sig); + lease_chan_max_msat = db_column_int(stmt, 11); + lease_chan_max_ppt = db_column_int(stmt, 12); + } else { + lease_commit_sig = NULL; + lease_chan_max_msat = 0; + lease_chan_max_ppt = 0; + } + inflight = new_inflight(chan, funding_txid, db_column_int(stmt, 1), db_column_int(stmt, 2), @@ -1063,7 +1078,11 @@ wallet_stmt2inflight(struct wallet *w, struct db_stmt *stmt, our_funding_sat, db_column_psbt(tmpctx, stmt, 5), db_column_psbt_to_tx(tmpctx, stmt, 6), - last_sig); + last_sig, + db_column_int(stmt, 9), + lease_commit_sig, + lease_chan_max_msat, + lease_chan_max_ppt); /* Pull out the serialized tx-sigs-received-ness */ inflight->remote_tx_sigs = db_column_int(stmt, 8); @@ -1086,6 +1105,10 @@ static bool wallet_channel_load_inflights(struct wallet *w, ", last_tx" // 6 ", last_sig" // 7 ", funding_tx_remote_sigs_received" //8 + ", lease_expiry" // 9 + ", lease_commit_sig" // 10 + ", lease_chan_max_msat" // 11 + ", lease_chan_max_ppt" // 12 " FROM channel_funding_inflights" " WHERE channel_id = ?" // ?0 " ORDER BY funding_feerate")); @@ -1133,6 +1156,9 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm struct pubkey *future_per_commitment_point; struct amount_sat funding_sat, our_funding_sat; struct amount_msat push_msat, our_msat, msat_to_us_min, msat_to_us_max; + secp256k1_ecdsa_signature *lease_commit_sig; + u32 lease_chan_max_msat; + u16 lease_chan_max_ppt; peer_dbid = db_column_u64(stmt, 1); peer = find_peer_by_dbid(w->ld, peer_dbid); @@ -1242,6 +1268,17 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm db_column_amount_msat(stmt, 40, &msat_to_us_min); db_column_amount_msat(stmt, 41, &msat_to_us_max); + if (!db_column_is_null(stmt, 61)) { + lease_commit_sig = tal(w, secp256k1_ecdsa_signature); + db_column_signature(stmt, 61, lease_commit_sig); + lease_chan_max_msat = db_column_int(stmt, 62); + lease_chan_max_ppt = db_column_int(stmt, 63); + } else { + lease_commit_sig = NULL; + lease_chan_max_msat = 0; + lease_chan_max_ppt = 0; + } + chan = new_channel(peer, db_column_u64(stmt, 0), &wshachain, db_column_int(stmt, 6), @@ -1292,7 +1329,11 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm db_column_int(stmt, 49), db_column_int(stmt, 51), db_column_int(stmt, 52), - shutdown_wrong_funding); + shutdown_wrong_funding, + db_column_int(stmt, 60), + lease_commit_sig, + lease_chan_max_msat, + lease_chan_max_ppt); if (!wallet_channel_load_inflights(w, chan)) { tal_free(chan); @@ -1384,6 +1425,10 @@ static bool wallet_channels_load_active(struct wallet *w) ", funding_pubkey_local" // 57 ", shutdown_wrong_txid" // 58 ", shutdown_wrong_outnum" // 59 + ", lease_expiry" // 60 + ", lease_commit_sig" // 61 + ", lease_chan_max_msat" // 62 + ", lease_chan_max_ppt" // 63 " FROM channels" " WHERE state != ?;")); //? 0 db_bind_int(stmt, 0, CLOSED); @@ -1671,8 +1716,12 @@ void wallet_channel_save(struct wallet *w, struct channel *chan) " closer=?," // 34 " state_change_reason=?," // 35 " shutdown_wrong_txid=?," // 36 - " shutdown_wrong_outnum=?" // 37 - " WHERE id=?")); // 38 + " shutdown_wrong_outnum=?," // 37 + " lease_expiry=?," // 38 + " lease_commit_sig=?," // 39 + " lease_chan_max_msat=?," // 40 + " lease_chan_max_ppt=?" // 41 + " WHERE id=?")); // 42 db_bind_u64(stmt, 0, chan->their_shachain.id); if (chan->scid) db_bind_short_channel_id(stmt, 1, chan->scid); @@ -1724,7 +1773,18 @@ void wallet_channel_save(struct wallet *w, struct channel *chan) db_bind_null(stmt, 36); db_bind_null(stmt, 37); } - db_bind_u64(stmt, 38, chan->dbid); + + db_bind_int(stmt, 38, chan->lease_expiry); + if (chan->lease_commit_sig) { + db_bind_signature(stmt, 39, chan->lease_commit_sig); + db_bind_int(stmt, 40, chan->lease_chan_max_msat); + db_bind_int(stmt, 41, chan->lease_chan_max_ppt); + } else { + db_bind_null(stmt, 39); + db_bind_null(stmt, 40); + db_bind_null(stmt, 41); + } + db_bind_u64(stmt, 42, chan->dbid); db_exec_prepared_v2(take(stmt)); wallet_channel_config_save(w, &chan->channel_info.their_config); From d8d5316f01093c0591622f0ab7d68d74998612f7 Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 6 Jul 2021 16:33:21 -0500 Subject: [PATCH 30/56] fixup: fold into next commit --- common/initial_channel.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/common/initial_channel.c b/common/initial_channel.c index 4c8c63c169e6..b32c5bd9713c 100644 --- a/common/initial_channel.c +++ b/common/initial_channel.c @@ -108,8 +108,11 @@ struct bitcoin_tx *initial_channel_tx(const tal_t *ctx, if (channel->lease_expiry == 0) csv_lock = 1; else - /* FIXME: */ - csv_lock = 1; + /* For the initial commitment, starts max lease */ + csv_lock = channel->lease_expiry + - get_blockheight(channel->blockheight_states, + channel->opener, + side); *wscript = bitcoin_redeem_2of2(ctx, &channel->funding_pubkey[side], From 0f79556fb13460d2e3e8858184f6d0eae2041078 Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 22 Jun 2021 13:25:59 -0500 Subject: [PATCH 31/56] liquidity-ads: persist channel blockheight states to disk Adds new tables to database, backfills, basically copies the fee_rates state machine for channeld. --- channeld/Makefile | 1 + channeld/channeld.c | 200 +++++- channeld/channeld_wire.csv | 8 + channeld/channeld_wiregen.c | 36 +- channeld/channeld_wiregen.h | 14 +- channeld/full_channel.c | 54 +- channeld/full_channel.h | 9 + channeld/test/run-full_channel.c | 4 + closingd/closingd_wiregen.c | 2 +- closingd/closingd_wiregen.h | 2 +- common/blockheight_states.c | 164 +++++ common/blockheight_states.h | 79 +++ common/initial_channel.c | 5 + common/initial_channel.h | 8 +- common/peer_status_wiregen.c | 2 +- common/peer_status_wiregen.h | 2 +- common/status_wiregen.c | 2 +- common/status_wiregen.h | 2 +- common/type_to_string.h | 1 + connectd/connectd_gossipd_wiregen.c | 2 +- connectd/connectd_gossipd_wiregen.h | 2 +- connectd/connectd_wiregen.c | 2 +- connectd/connectd_wiregen.h | 2 +- devtools/Makefile | 1 + devtools/mkcommit.c | 4 + 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 +- lightningd/Makefile | 1 + lightningd/channel.c | 17 +- lightningd/channel.h | 8 +- lightningd/channel_control.c | 45 +- lightningd/dual_open_control.c | 31 +- lightningd/opening_control.c | 4 + lightningd/peer_control.c | 5 + lightningd/test/run-invoice-select-inchan.c | 5 + onchaind/onchaind_wiregen.c | 2 +- onchaind/onchaind_wiregen.h | 2 +- openingd/Makefile | 1 + openingd/dualopend.c | 37 +- openingd/dualopend_wire.csv | 2 + openingd/dualopend_wiregen.c | 14 +- openingd/dualopend_wiregen.h | 10 +- openingd/openingd.c | 4 +- openingd/openingd_wiregen.c | 2 +- openingd/openingd_wiregen.h | 2 +- tests/fuzz/fuzz-initial_channel.c | 24 +- tools/generate-wire.py | 1 + wallet/db.c | 39 ++ wallet/db_postgres_sqlgen.c | 56 +- wallet/db_sqlite3_sqlgen.c | 56 +- wallet/statements_gettextgen.po | 652 ++++++++++---------- wallet/test/Makefile | 1 + wallet/test/run-wallet.c | 55 +- wallet/wallet.c | 120 +++- wire/common_wiregen.c | 2 +- wire/common_wiregen.h | 2 +- 62 files changed, 1395 insertions(+), 429 deletions(-) create mode 100644 common/blockheight_states.c create mode 100644 common/blockheight_states.h diff --git a/channeld/Makefile b/channeld/Makefile index c3b9b16114c2..8fb4cc12ff87 100644 --- a/channeld/Makefile +++ b/channeld/Makefile @@ -35,6 +35,7 @@ CHANNELD_COMMON_OBJS := \ common/billboard.o \ common/bip32.o \ common/blinding.o \ + common/blockheight_states.o \ common/channel_config.o \ common/channel_id.o \ common/crypto_state.o \ diff --git a/channeld/channeld.c b/channeld/channeld.c index 35b430756662..c8479b0471d0 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -134,6 +134,9 @@ struct peer { /* The feerate we want. */ u32 desired_feerate; + /* Current blockheight */ + u32 our_blockheight; + /* Announcement related information */ struct node_id node_ids[NUM_SIDES]; struct short_channel_id short_channel_ids[NUM_SIDES]; @@ -837,6 +840,75 @@ static void handle_peer_feechange(struct peer *peer, const u8 *msg) status_debug("peer updated fee to %u", feerate); } +static void handle_peer_blockheight_change(struct peer *peer, const u8 *msg) +{ + struct channel_id channel_id; + u32 blockheight, current; + + if (!fromwire_update_blockheight(msg, &channel_id, &blockheight)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Bad update_blockheight %s", + tal_hex(msg, msg)); + + /* BOLT- #2: + * A receiving node: + * ... + * - if the sender is not the initiator: + * - MUST fail the channel. + */ + if (peer->channel->opener != REMOTE) + peer_failed_warn(peer->pps, &peer->channel_id, + "update_blockheight from non-opener?"); + + current = get_blockheight(peer->channel->blockheight_states, + peer->channel->opener, LOCAL); + + status_debug("update_blockheight %u. last update height %u," + " our current height %u", + blockheight, current, peer->our_blockheight); + + /* BOLT- #2: + * A receiving node: + * - if the `update_blockheight` is less than the last + * received `blockheight`: + * - SHOULD fail the channel. + * ... + * - if `blockheight` is more than 1008 blocks behind + * the current blockheight: + * - SHOULD fail the channel + */ + /* Overflow check */ + if (blockheight + 1008 < blockheight) + peer_failed_warn(peer->pps, &peer->channel_id, + "blockheight + 1008 overflow (%u)", + blockheight); + + /* If they're behind the last one they sent, we just warn and + * reconnect, as they might be catching up */ + /* FIXME: track for how long they send backwards blockheight? */ + if (blockheight < current) + peer_failed_warn(peer->pps, &peer->channel_id, + "update_blockheight %u older than previous %u", + blockheight, current); + + /* BOLT- #2: + * A receiving node: + * ... + * - if `blockheight` is more than 1008 blocks behind + * the current blockheight: + * - SHOULD fail the channel + */ + assert(blockheight < blockheight + 1008); + if (blockheight + 1008 < peer->our_blockheight) + peer_failed_err(peer->pps, &peer->channel_id, + "update_blockheight %u outside" + " permissible range", blockheight); + + channel_update_blockheight(peer->channel, blockheight); + + status_debug("peer updated blockheight to %u", blockheight); +} + static struct changed_htlc *changed_htlc_arr(const tal_t *ctx, const struct htlc **changed_htlcs) { @@ -1122,6 +1194,41 @@ static bool want_fee_update(const struct peer *peer, u32 *target) return val != channel_feerate(peer->channel, REMOTE); } +/* Do we want to update blockheight? */ +static bool want_blockheight_update(const struct peer *peer, u32 *height) +{ + u32 last; + + if (peer->channel->opener != LOCAL) + return false; + + if (peer->channel->lease_expiry == 0) + return false; + +#if EXPERIMENTAL_FEATURES + /* No fee update while quiescing! */ + if (peer->stfu) + return false; +#endif + /* What's the current blockheight */ + last = get_blockheight(peer->channel->blockheight_states, + peer->channel->opener, LOCAL); + + if (peer->our_blockheight < last) { + status_broken("current blockheight %u less than last %u", + peer->our_blockheight, last); + return false; + } + + if (peer->our_blockheight == last) + return false; + + if (height) + *height = peer->our_blockheight; + + return true; +} + static void send_commit(struct peer *peer) { u8 *msg; @@ -1132,6 +1239,7 @@ static void send_commit(struct peer *peer) const struct htlc **htlc_map; struct wally_tx_output *direct_outputs[NUM_SIDES]; struct penalty_base *pbase; + u32 our_blockheight; u32 feerate_target; #if DEVELOPER @@ -1200,6 +1308,22 @@ static void send_commit(struct peer *peer) } } + if (want_blockheight_update(peer, &our_blockheight)) { + if (blockheight_changes_done(peer->channel->blockheight_states, + false)) { + u8 *msg; + + channel_update_blockheight(peer->channel, + our_blockheight); + + msg = towire_update_blockheight(NULL, + &peer->channel_id, + our_blockheight); + + sync_crypto_write(peer->pps, take(msg)); + } + } + /* BOLT #2: * * A sending node: @@ -1208,9 +1332,13 @@ static void send_commit(struct peer *peer) */ changed_htlcs = tal_arr(tmpctx, const struct htlc *, 0); if (!channel_sending_commit(peer->channel, &changed_htlcs)) { - status_debug("Can't send commit: nothing to send, feechange %s (%s)", + status_debug("Can't send commit: nothing to send," + " feechange %s (%s)" + " blockheight %s (%s)", want_fee_update(peer, NULL) ? "wanted": "not wanted", - type_to_string(tmpctx, struct fee_states, peer->channel->fee_states)); + type_to_string(tmpctx, struct fee_states, peer->channel->fee_states), + want_blockheight_update(peer, NULL) ? "wanted" : "not wanted", + type_to_string(tmpctx, struct height_states, peer->channel->blockheight_states)); /* Covers the case where we've just been told to shutdown. */ maybe_send_shutdown(peer); @@ -2085,8 +2213,8 @@ static void peer_in(struct peer *peer, const u8 *msg) handle_peer_feechange(peer, msg); return; case WIRE_UPDATE_BLOCKHEIGHT: - /* FIXME: do this! */ - break; + handle_peer_blockheight_change(peer, msg); + return; case WIRE_REVOKE_AND_ACK: handle_peer_revoke_and_ack(peer, msg); return; @@ -3127,6 +3255,49 @@ static void handle_feerates(struct peer *peer, const u8 *inmsg) } } +static void handle_blockheight(struct peer *peer, const u8 *inmsg) +{ + u32 blockheight; + + if (!fromwire_channeld_blockheight(inmsg, &blockheight)) + master_badmsg(WIRE_CHANNELD_BLOCKHEIGHT, inmsg); + + /* Save it, so we know */ + peer->our_blockheight = blockheight; + if (peer->channel->opener == LOCAL) + start_commit_timer(peer); + else { + u32 peer_height = get_blockheight(peer->channel->blockheight_states, + peer->channel->opener, + REMOTE); + /* BOLT- #2: + * The node _not responsible_ for initiating the channel: + * ... + * - if last received `blockheight` is > 1008 behind + * currently known blockheight: + * - SHOULD fail he channel + */ + assert(peer_height + 1008 > peer_height); + if (peer_height + 1008 < blockheight) + peer_failed_err(peer->pps, &peer->channel_id, + "Peer is too far behind, terminating" + " leased channel. Our current" + " %u, theirs %u", + blockheight, peer_height); + /* We're behind them... what do. It's possible they're lying, + * but if we're in a lease this is actually in our favor so + * we log it but otherwise continue on unchanged */ + if (peer_height > blockheight + && peer_height > blockheight + 100) + status_unusual("Peer reporting we've fallen %u" + " blocks behind. Our height %u," + " their height %u", + peer_height - blockheight, + blockheight, peer_height); + + } +} + static void handle_specific_feerates(struct peer *peer, const u8 *inmsg) { u32 base_old = peer->fee_base; @@ -3305,6 +3476,11 @@ static void req_in(struct peer *peer, const u8 *msg) return; handle_feerates(peer, msg); return; + case WIRE_CHANNELD_BLOCKHEIGHT: + if (handle_master_request_later(peer, msg)) + return; + handle_blockheight(peer, msg); + return; case WIRE_CHANNELD_FULFILL_HTLC: if (handle_master_request_later(peer, msg)) return; @@ -3397,7 +3573,8 @@ static void init_channel(struct peer *peer) u8 *fwd_msg; const u8 *msg; struct fee_states *fee_states; - u32 minimum_depth; + struct height_states *blockheight_states; + u32 minimum_depth, lease_expiry; struct secret last_remote_per_commit_secret; secp256k1_ecdsa_signature *remote_ann_node_sig; secp256k1_ecdsa_signature *remote_ann_bitcoin_sig; @@ -3417,6 +3594,9 @@ static void init_channel(struct peer *peer) &funding_txid, &funding_txout, &funding, &minimum_depth, + &peer->our_blockheight, + &blockheight_states, + &lease_expiry, &conf[LOCAL], &conf[REMOTE], &fee_states, &peer->feerate_min, @@ -3486,7 +3666,8 @@ static void init_channel(struct peer *peer) " next_idx_local = %"PRIu64 " next_idx_remote = %"PRIu64 " revocations_received = %"PRIu64 - " feerates %s range %u-%u", + " feerates %s range %u-%u" + " blockheights %s, our current %u", side_to_str(opener), type_to_string(tmpctx, struct pubkey, &peer->remote_per_commit), @@ -3495,7 +3676,9 @@ static void init_channel(struct peer *peer) peer->next_index[LOCAL], peer->next_index[REMOTE], peer->revocations_received, type_to_string(tmpctx, struct fee_states, fee_states), - peer->feerate_min, peer->feerate_max); + peer->feerate_min, peer->feerate_max, + type_to_string(tmpctx, struct height_states, blockheight_states), + peer->our_blockheight); status_debug("option_static_remotekey = %u", option_static_remotekey); @@ -3525,7 +3708,8 @@ static void init_channel(struct peer *peer) &funding_txid, funding_txout, minimum_depth, - 0, /* FIXME: channel lease_expiry */ + take(blockheight_states), + lease_expiry, funding, local_msat, take(fee_states), diff --git a/channeld/channeld_wire.csv b/channeld/channeld_wire.csv index 8af0756a34a1..07efef0fc210 100644 --- a/channeld/channeld_wire.csv +++ b/channeld/channeld_wire.csv @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -17,6 +18,9 @@ msgdata,channeld_init,funding_txid,bitcoin_txid, msgdata,channeld_init,funding_txout,u16, msgdata,channeld_init,funding_satoshi,amount_sat, msgdata,channeld_init,minimum_depth,u32, +msgdata,channeld_init,our_blockheight,u32, +msgdata,channeld_init,blockheight_states,height_states, +msgdata,channeld_init,lease_expiry,u32, msgdata,channeld_init,our_config,channel_config, msgdata,channeld_init,their_config,channel_config, msgdata,channeld_init,fee_states,fee_states, @@ -225,3 +229,7 @@ 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, + +# Tell peer about our latest and greatest blockheight. +msgtype,channeld_blockheight,1012 +msgdata,channeld_blockheight,blockheight,u32, diff --git a/channeld/channeld_wiregen.c b/channeld/channeld_wiregen.c index 0a4d375bc327..06bb5f9a81ae 100644 --- a/channeld/channeld_wiregen.c +++ b/channeld/channeld_wiregen.c @@ -49,6 +49,7 @@ const char *channeld_wire_name(int e) 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"; + case WIRE_CHANNELD_BLOCKHEIGHT: return "WIRE_CHANNELD_BLOCKHEIGHT"; } snprintf(invalidbuf, sizeof(invalidbuf), "INVALID %i", e); @@ -87,6 +88,7 @@ bool channeld_wire_is_defined(u16 type) case WIRE_CHANNELD_DEV_QUIESCE:; case WIRE_CHANNELD_DEV_QUIESCE_REPLY:; case WIRE_CHANNELD_UPGRADED:; + case WIRE_CHANNELD_BLOCKHEIGHT:; return true; } return false; @@ -98,7 +100,7 @@ bool channeld_wire_is_defined(u16 type) /* WIRE: CHANNELD_INIT */ /* Begin! (passes gossipd-client fd) */ -u8 *towire_channeld_init(const tal_t *ctx, const struct chainparams *chainparams, const struct feature_set *our_features, const struct channel_id *channel_id, const struct bitcoin_txid *funding_txid, u16 funding_txout, struct amount_sat funding_satoshi, u32 minimum_depth, const struct channel_config *our_config, const struct channel_config *their_config, const struct fee_states *fee_states, u32 feerate_min, u32 feerate_max, u32 feerate_penalty, const struct bitcoin_signature *first_commit_sig, const struct per_peer_state *per_peer_state, const struct pubkey *remote_fundingkey, const struct basepoints *remote_basepoints, const struct pubkey *remote_per_commit, const struct pubkey *old_remote_per_commit, enum side opener, u32 fee_base, u32 fee_proportional, struct amount_msat local_msatoshi, const struct basepoints *our_basepoints, const struct pubkey *our_funding_pubkey, const struct node_id *local_node_id, const struct node_id *remote_node_id, u32 commit_msec, u16 cltv_delta, bool last_was_revoke, const struct changed_htlc *last_sent_commit, u64 next_index_local, u64 next_index_remote, u64 revocations_received, u64 next_htlc_id, const struct existing_htlc **htlcs, bool local_funding_locked, bool remote_funding_locked, const struct short_channel_id *funding_short_id, bool reestablish, bool send_shutdown, bool remote_shutdown_received, const u8 *final_scriptpubkey, u8 flags, const u8 *init_peer_pkt, bool reached_announce_depth, const struct secret *last_remote_secret, const u8 *their_features, const u8 *upfront_shutdown_script, const secp256k1_ecdsa_signature *remote_ann_node_sig, const secp256k1_ecdsa_signature *remote_ann_bitcoin_sig, bool option_static_remotekey, bool option_anchor_outputs, bool dev_fast_gossip, bool dev_fail_process_onionpacket, const struct penalty_base *pbases) +u8 *towire_channeld_init(const tal_t *ctx, const struct chainparams *chainparams, const struct feature_set *our_features, const struct channel_id *channel_id, const struct bitcoin_txid *funding_txid, u16 funding_txout, struct amount_sat funding_satoshi, u32 minimum_depth, u32 our_blockheight, const struct height_states *blockheight_states, u32 lease_expiry, const struct channel_config *our_config, const struct channel_config *their_config, const struct fee_states *fee_states, u32 feerate_min, u32 feerate_max, u32 feerate_penalty, const struct bitcoin_signature *first_commit_sig, const struct per_peer_state *per_peer_state, const struct pubkey *remote_fundingkey, const struct basepoints *remote_basepoints, const struct pubkey *remote_per_commit, const struct pubkey *old_remote_per_commit, enum side opener, u32 fee_base, u32 fee_proportional, struct amount_msat local_msatoshi, const struct basepoints *our_basepoints, const struct pubkey *our_funding_pubkey, const struct node_id *local_node_id, const struct node_id *remote_node_id, u32 commit_msec, u16 cltv_delta, bool last_was_revoke, const struct changed_htlc *last_sent_commit, u64 next_index_local, u64 next_index_remote, u64 revocations_received, u64 next_htlc_id, const struct existing_htlc **htlcs, bool local_funding_locked, bool remote_funding_locked, const struct short_channel_id *funding_short_id, bool reestablish, bool send_shutdown, bool remote_shutdown_received, const u8 *final_scriptpubkey, u8 flags, const u8 *init_peer_pkt, bool reached_announce_depth, const struct secret *last_remote_secret, const u8 *their_features, const u8 *upfront_shutdown_script, const secp256k1_ecdsa_signature *remote_ann_node_sig, const secp256k1_ecdsa_signature *remote_ann_bitcoin_sig, bool option_static_remotekey, bool option_anchor_outputs, bool dev_fast_gossip, bool dev_fail_process_onionpacket, const struct penalty_base *pbases) { u16 num_last_sent_commit = tal_count(last_sent_commit); u16 num_existing_htlcs = tal_count(htlcs); @@ -117,6 +119,9 @@ u8 *towire_channeld_init(const tal_t *ctx, const struct chainparams *chainparams towire_u16(&p, funding_txout); towire_amount_sat(&p, funding_satoshi); towire_u32(&p, minimum_depth); + towire_u32(&p, our_blockheight); + towire_height_states(&p, blockheight_states); + towire_u32(&p, lease_expiry); towire_channel_config(&p, our_config); towire_channel_config(&p, their_config); towire_fee_states(&p, fee_states); @@ -189,7 +194,7 @@ u8 *towire_channeld_init(const tal_t *ctx, const struct chainparams *chainparams return memcheck(p, tal_count(p)); } -bool fromwire_channeld_init(const tal_t *ctx, const void *p, const struct chainparams **chainparams, struct feature_set **our_features, struct channel_id *channel_id, struct bitcoin_txid *funding_txid, u16 *funding_txout, struct amount_sat *funding_satoshi, u32 *minimum_depth, struct channel_config *our_config, struct channel_config *their_config, struct fee_states **fee_states, u32 *feerate_min, u32 *feerate_max, u32 *feerate_penalty, struct bitcoin_signature *first_commit_sig, struct per_peer_state **per_peer_state, struct pubkey *remote_fundingkey, struct basepoints *remote_basepoints, struct pubkey *remote_per_commit, struct pubkey *old_remote_per_commit, enum side *opener, u32 *fee_base, u32 *fee_proportional, struct amount_msat *local_msatoshi, struct basepoints *our_basepoints, struct pubkey *our_funding_pubkey, struct node_id *local_node_id, struct node_id *remote_node_id, u32 *commit_msec, u16 *cltv_delta, bool *last_was_revoke, struct changed_htlc **last_sent_commit, u64 *next_index_local, u64 *next_index_remote, u64 *revocations_received, u64 *next_htlc_id, struct existing_htlc ***htlcs, bool *local_funding_locked, bool *remote_funding_locked, struct short_channel_id *funding_short_id, bool *reestablish, bool *send_shutdown, bool *remote_shutdown_received, u8 **final_scriptpubkey, u8 *flags, u8 **init_peer_pkt, bool *reached_announce_depth, struct secret *last_remote_secret, u8 **their_features, u8 **upfront_shutdown_script, secp256k1_ecdsa_signature **remote_ann_node_sig, secp256k1_ecdsa_signature **remote_ann_bitcoin_sig, bool *option_static_remotekey, bool *option_anchor_outputs, bool *dev_fast_gossip, bool *dev_fail_process_onionpacket, struct penalty_base **pbases) +bool fromwire_channeld_init(const tal_t *ctx, const void *p, const struct chainparams **chainparams, struct feature_set **our_features, struct channel_id *channel_id, struct bitcoin_txid *funding_txid, u16 *funding_txout, struct amount_sat *funding_satoshi, u32 *minimum_depth, u32 *our_blockheight, struct height_states **blockheight_states, u32 *lease_expiry, struct channel_config *our_config, struct channel_config *their_config, struct fee_states **fee_states, u32 *feerate_min, u32 *feerate_max, u32 *feerate_penalty, struct bitcoin_signature *first_commit_sig, struct per_peer_state **per_peer_state, struct pubkey *remote_fundingkey, struct basepoints *remote_basepoints, struct pubkey *remote_per_commit, struct pubkey *old_remote_per_commit, enum side *opener, u32 *fee_base, u32 *fee_proportional, struct amount_msat *local_msatoshi, struct basepoints *our_basepoints, struct pubkey *our_funding_pubkey, struct node_id *local_node_id, struct node_id *remote_node_id, u32 *commit_msec, u16 *cltv_delta, bool *last_was_revoke, struct changed_htlc **last_sent_commit, u64 *next_index_local, u64 *next_index_remote, u64 *revocations_received, u64 *next_htlc_id, struct existing_htlc ***htlcs, bool *local_funding_locked, bool *remote_funding_locked, struct short_channel_id *funding_short_id, bool *reestablish, bool *send_shutdown, bool *remote_shutdown_received, u8 **final_scriptpubkey, u8 *flags, u8 **init_peer_pkt, bool *reached_announce_depth, struct secret *last_remote_secret, u8 **their_features, u8 **upfront_shutdown_script, secp256k1_ecdsa_signature **remote_ann_node_sig, secp256k1_ecdsa_signature **remote_ann_bitcoin_sig, bool *option_static_remotekey, bool *option_anchor_outputs, bool *dev_fast_gossip, bool *dev_fail_process_onionpacket, struct penalty_base **pbases) { u16 num_last_sent_commit; u16 num_existing_htlcs; @@ -211,6 +216,9 @@ bool fromwire_channeld_init(const tal_t *ctx, const void *p, const struct chainp *funding_txout = fromwire_u16(&cursor, &plen); *funding_satoshi = fromwire_amount_sat(&cursor, &plen); *minimum_depth = fromwire_u32(&cursor, &plen); + *our_blockheight = fromwire_u32(&cursor, &plen); + *blockheight_states = fromwire_height_states(ctx, &cursor, &plen); + *lease_expiry = fromwire_u32(&cursor, &plen); fromwire_channel_config(&cursor, &plen, our_config); fromwire_channel_config(&cursor, &plen, their_config); *fee_states = fromwire_fee_states(ctx, &cursor, &plen); @@ -1137,4 +1145,26 @@ bool fromwire_channeld_upgraded(const void *p, bool *option_static_remotekey) *option_static_remotekey = fromwire_bool(&cursor, &plen); return cursor != NULL; } -// SHA256STAMP:2d7b763e89512ad8c5921b90c13f37ac83ab0016384c38e8c8e831683d668651 + +/* WIRE: CHANNELD_BLOCKHEIGHT */ +/* Tell peer about our latest and greatest blockheight. */ +u8 *towire_channeld_blockheight(const tal_t *ctx, u32 blockheight) +{ + u8 *p = tal_arr(ctx, u8, 0); + + towire_u16(&p, WIRE_CHANNELD_BLOCKHEIGHT); + towire_u32(&p, blockheight); + + return memcheck(p, tal_count(p)); +} +bool fromwire_channeld_blockheight(const void *p, u32 *blockheight) +{ + const u8 *cursor = p; + size_t plen = tal_count(p); + + if (fromwire_u16(&cursor, &plen) != WIRE_CHANNELD_BLOCKHEIGHT) + return false; + *blockheight = fromwire_u32(&cursor, &plen); + return cursor != NULL; +} +// SHA256STAMP:943ce198f20b823bbf667e253b66b1810caa3aac410e55744ac0cbeb7438904a diff --git a/channeld/channeld_wiregen.h b/channeld/channeld_wiregen.h index 3dde409668f6..3b4bb4b0b6e4 100644 --- a/channeld/channeld_wiregen.h +++ b/channeld/channeld_wiregen.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -75,6 +76,8 @@ enum channeld_wire { WIRE_CHANNELD_DEV_QUIESCE_REPLY = 1109, /* Tell master we're upgrading the commitment tx. */ WIRE_CHANNELD_UPGRADED = 1011, + /* Tell peer about our latest and greatest blockheight. */ + WIRE_CHANNELD_BLOCKHEIGHT = 1012, }; const char *channeld_wire_name(int e); @@ -91,8 +94,8 @@ bool channeld_wire_is_defined(u16 type); /* WIRE: CHANNELD_INIT */ /* Begin! (passes gossipd-client fd) */ -u8 *towire_channeld_init(const tal_t *ctx, const struct chainparams *chainparams, const struct feature_set *our_features, const struct channel_id *channel_id, const struct bitcoin_txid *funding_txid, u16 funding_txout, struct amount_sat funding_satoshi, u32 minimum_depth, const struct channel_config *our_config, const struct channel_config *their_config, const struct fee_states *fee_states, u32 feerate_min, u32 feerate_max, u32 feerate_penalty, const struct bitcoin_signature *first_commit_sig, const struct per_peer_state *per_peer_state, const struct pubkey *remote_fundingkey, const struct basepoints *remote_basepoints, const struct pubkey *remote_per_commit, const struct pubkey *old_remote_per_commit, enum side opener, u32 fee_base, u32 fee_proportional, struct amount_msat local_msatoshi, const struct basepoints *our_basepoints, const struct pubkey *our_funding_pubkey, const struct node_id *local_node_id, const struct node_id *remote_node_id, u32 commit_msec, u16 cltv_delta, bool last_was_revoke, const struct changed_htlc *last_sent_commit, u64 next_index_local, u64 next_index_remote, u64 revocations_received, u64 next_htlc_id, const struct existing_htlc **htlcs, bool local_funding_locked, bool remote_funding_locked, const struct short_channel_id *funding_short_id, bool reestablish, bool send_shutdown, bool remote_shutdown_received, const u8 *final_scriptpubkey, u8 flags, const u8 *init_peer_pkt, bool reached_announce_depth, const struct secret *last_remote_secret, const u8 *their_features, const u8 *upfront_shutdown_script, const secp256k1_ecdsa_signature *remote_ann_node_sig, const secp256k1_ecdsa_signature *remote_ann_bitcoin_sig, bool option_static_remotekey, bool option_anchor_outputs, bool dev_fast_gossip, bool dev_fail_process_onionpacket, const struct penalty_base *pbases); -bool fromwire_channeld_init(const tal_t *ctx, const void *p, const struct chainparams **chainparams, struct feature_set **our_features, struct channel_id *channel_id, struct bitcoin_txid *funding_txid, u16 *funding_txout, struct amount_sat *funding_satoshi, u32 *minimum_depth, struct channel_config *our_config, struct channel_config *their_config, struct fee_states **fee_states, u32 *feerate_min, u32 *feerate_max, u32 *feerate_penalty, struct bitcoin_signature *first_commit_sig, struct per_peer_state **per_peer_state, struct pubkey *remote_fundingkey, struct basepoints *remote_basepoints, struct pubkey *remote_per_commit, struct pubkey *old_remote_per_commit, enum side *opener, u32 *fee_base, u32 *fee_proportional, struct amount_msat *local_msatoshi, struct basepoints *our_basepoints, struct pubkey *our_funding_pubkey, struct node_id *local_node_id, struct node_id *remote_node_id, u32 *commit_msec, u16 *cltv_delta, bool *last_was_revoke, struct changed_htlc **last_sent_commit, u64 *next_index_local, u64 *next_index_remote, u64 *revocations_received, u64 *next_htlc_id, struct existing_htlc ***htlcs, bool *local_funding_locked, bool *remote_funding_locked, struct short_channel_id *funding_short_id, bool *reestablish, bool *send_shutdown, bool *remote_shutdown_received, u8 **final_scriptpubkey, u8 *flags, u8 **init_peer_pkt, bool *reached_announce_depth, struct secret *last_remote_secret, u8 **their_features, u8 **upfront_shutdown_script, secp256k1_ecdsa_signature **remote_ann_node_sig, secp256k1_ecdsa_signature **remote_ann_bitcoin_sig, bool *option_static_remotekey, bool *option_anchor_outputs, bool *dev_fast_gossip, bool *dev_fail_process_onionpacket, struct penalty_base **pbases); +u8 *towire_channeld_init(const tal_t *ctx, const struct chainparams *chainparams, const struct feature_set *our_features, const struct channel_id *channel_id, const struct bitcoin_txid *funding_txid, u16 funding_txout, struct amount_sat funding_satoshi, u32 minimum_depth, u32 our_blockheight, const struct height_states *blockheight_states, u32 lease_expiry, const struct channel_config *our_config, const struct channel_config *their_config, const struct fee_states *fee_states, u32 feerate_min, u32 feerate_max, u32 feerate_penalty, const struct bitcoin_signature *first_commit_sig, const struct per_peer_state *per_peer_state, const struct pubkey *remote_fundingkey, const struct basepoints *remote_basepoints, const struct pubkey *remote_per_commit, const struct pubkey *old_remote_per_commit, enum side opener, u32 fee_base, u32 fee_proportional, struct amount_msat local_msatoshi, const struct basepoints *our_basepoints, const struct pubkey *our_funding_pubkey, const struct node_id *local_node_id, const struct node_id *remote_node_id, u32 commit_msec, u16 cltv_delta, bool last_was_revoke, const struct changed_htlc *last_sent_commit, u64 next_index_local, u64 next_index_remote, u64 revocations_received, u64 next_htlc_id, const struct existing_htlc **htlcs, bool local_funding_locked, bool remote_funding_locked, const struct short_channel_id *funding_short_id, bool reestablish, bool send_shutdown, bool remote_shutdown_received, const u8 *final_scriptpubkey, u8 flags, const u8 *init_peer_pkt, bool reached_announce_depth, const struct secret *last_remote_secret, const u8 *their_features, const u8 *upfront_shutdown_script, const secp256k1_ecdsa_signature *remote_ann_node_sig, const secp256k1_ecdsa_signature *remote_ann_bitcoin_sig, bool option_static_remotekey, bool option_anchor_outputs, bool dev_fast_gossip, bool dev_fail_process_onionpacket, const struct penalty_base *pbases); +bool fromwire_channeld_init(const tal_t *ctx, const void *p, const struct chainparams **chainparams, struct feature_set **our_features, struct channel_id *channel_id, struct bitcoin_txid *funding_txid, u16 *funding_txout, struct amount_sat *funding_satoshi, u32 *minimum_depth, u32 *our_blockheight, struct height_states **blockheight_states, u32 *lease_expiry, struct channel_config *our_config, struct channel_config *their_config, struct fee_states **fee_states, u32 *feerate_min, u32 *feerate_max, u32 *feerate_penalty, struct bitcoin_signature *first_commit_sig, struct per_peer_state **per_peer_state, struct pubkey *remote_fundingkey, struct basepoints *remote_basepoints, struct pubkey *remote_per_commit, struct pubkey *old_remote_per_commit, enum side *opener, u32 *fee_base, u32 *fee_proportional, struct amount_msat *local_msatoshi, struct basepoints *our_basepoints, struct pubkey *our_funding_pubkey, struct node_id *local_node_id, struct node_id *remote_node_id, u32 *commit_msec, u16 *cltv_delta, bool *last_was_revoke, struct changed_htlc **last_sent_commit, u64 *next_index_local, u64 *next_index_remote, u64 *revocations_received, u64 *next_htlc_id, struct existing_htlc ***htlcs, bool *local_funding_locked, bool *remote_funding_locked, struct short_channel_id *funding_short_id, bool *reestablish, bool *send_shutdown, bool *remote_shutdown_received, u8 **final_scriptpubkey, u8 *flags, u8 **init_peer_pkt, bool *reached_announce_depth, struct secret *last_remote_secret, u8 **their_features, u8 **upfront_shutdown_script, secp256k1_ecdsa_signature **remote_ann_node_sig, secp256k1_ecdsa_signature **remote_ann_bitcoin_sig, bool *option_static_remotekey, bool *option_anchor_outputs, bool *dev_fast_gossip, bool *dev_fail_process_onionpacket, struct penalty_base **pbases); /* WIRE: CHANNELD_FUNDING_DEPTH */ /* master->channeld funding hit new depth(funding locked if >= lock depth) */ @@ -230,6 +233,11 @@ bool fromwire_channeld_dev_quiesce_reply(const void *p); u8 *towire_channeld_upgraded(const tal_t *ctx, bool option_static_remotekey); bool fromwire_channeld_upgraded(const void *p, bool *option_static_remotekey); +/* WIRE: CHANNELD_BLOCKHEIGHT */ +/* Tell peer about our latest and greatest blockheight. */ +u8 *towire_channeld_blockheight(const tal_t *ctx, u32 blockheight); +bool fromwire_channeld_blockheight(const void *p, u32 *blockheight); + #endif /* LIGHTNING_CHANNELD_CHANNELD_WIREGEN_H */ -// SHA256STAMP:2d7b763e89512ad8c5921b90c13f37ac83ab0016384c38e8c8e831683d668651 +// SHA256STAMP:943ce198f20b823bbf667e253b66b1810caa3aac410e55744ac0cbeb7438904a diff --git a/channeld/full_channel.c b/channeld/full_channel.c index 3418dee0651f..684859a500db 100644 --- a/channeld/full_channel.c +++ b/channeld/full_channel.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -95,6 +96,7 @@ struct channel *new_full_channel(const tal_t *ctx, const struct bitcoin_txid *funding_txid, unsigned int funding_txout, u32 minimum_depth, + const struct height_states *blockheight_states, u32 lease_expiry, struct amount_sat funding, struct amount_msat local_msat, @@ -114,6 +116,7 @@ struct channel *new_full_channel(const tal_t *ctx, funding_txid, funding_txout, minimum_depth, + blockheight_states, lease_expiry, funding, local_msat, @@ -979,6 +982,34 @@ static bool fee_incstate(struct channel *channel, return true; } +static bool blockheight_incstate(struct channel *channel, + enum side sidechanged, + enum htlc_state hstate) +{ + int preflags, postflags; + + preflags = htlc_state_flags(hstate); + postflags = htlc_state_flags(hstate + 1); + + /* You can't change sides. */ + assert((preflags & (HTLC_LOCAL_F_OWNER|HTLC_REMOTE_F_OWNER)) + == (postflags & (HTLC_LOCAL_F_OWNER|HTLC_REMOTE_F_OWNER))); + + /* These only advance through ADDING states. */ + if (!(htlc_state_flags(hstate) & HTLC_ADDING)) + return false; + + if (!inc_height_state(channel->blockheight_states, hstate)) + return false; + + status_debug("Blockheight: %s->%s %s now %u", + htlc_state_name(hstate), + htlc_state_name(hstate+1), + side_to_str(sidechanged), + *channel->blockheight_states->height[hstate+1]); + return true; +} + /* Returns flags which were changed. */ static int change_htlcs(struct channel *channel, enum side sidechanged, @@ -1022,11 +1053,16 @@ static int change_htlcs(struct channel *channel, } } - /* Update fees (do backwards, to avoid double-increment!). */ + /* Update fees and blockheight (do backwards, to avoid + * double-increment!). */ for (i = n_hstates - 1; i >= 0; i--) { if (fee_incstate(channel, sidechanged, htlc_states[i])) cflags |= (htlc_state_flags(htlc_states[i]) ^ htlc_state_flags(htlc_states[i]+1)); + + if (blockheight_incstate(channel, sidechanged, htlc_states[i])) + cflags |= (htlc_state_flags(htlc_states[i]) + ^ htlc_state_flags(htlc_states[i]+1)); } return cflags; @@ -1154,6 +1190,16 @@ bool channel_update_feerate(struct channel *channel, u32 feerate_per_kw) return true; } +void channel_update_blockheight(struct channel *channel, + u32 blockheight) +{ + status_debug("Setting %s blockheight to %u", + side_to_str(!channel->opener), blockheight); + + start_height_update(channel->blockheight_states, channel->opener, + blockheight); +} + bool channel_sending_commit(struct channel *channel, const struct htlc ***htlcs) { @@ -1278,10 +1324,14 @@ bool pending_updates(const struct channel *channel, struct htlc_map_iter it; const struct htlc *htlc; - /* Initiator might have fee changes in play. */ + /* Initiator might have fee changes or blockheight updates in play. */ if (side == channel->opener) { if (!feerate_changes_done(channel->fee_states, uncommitted_ok)) return true; + + if (!blockheight_changes_done(channel->blockheight_states, + uncommitted_ok)) + return true; } for (htlc = htlc_map_first(channel->htlcs, &it); diff --git a/channeld/full_channel.h b/channeld/full_channel.h index c7151ddb6fd2..56b7c1514aa1 100644 --- a/channeld/full_channel.h +++ b/channeld/full_channel.h @@ -17,6 +17,7 @@ struct existing_htlc; * @funding_txid: The commitment transaction id. * @funding_txout: The commitment transaction output number. * @minimum_depth: The minimum confirmations needed for funding transaction. + * @blockheight_states: The blockheight update states. * @lease_expiry: The block the lease on this channel expires at; 0 if no lease. * @funding: The commitment transaction amount. * @local_msat: The amount for the local side (remainder goes to remote) @@ -38,6 +39,7 @@ struct channel *new_full_channel(const tal_t *ctx, const struct bitcoin_txid *funding_txid, unsigned int funding_txout, u32 minimum_depth, + const struct height_states *blockheight_states, u32 lease_expiry, struct amount_sat funding, struct amount_msat local_msat, @@ -184,6 +186,13 @@ bool can_opener_afford_feerate(const struct channel *channel, u32 feerate); */ bool channel_update_feerate(struct channel *channel, u32 feerate_per_kw); +/* + * channel_update_blockheight: Change blockheight on non-opener side. + * @channel: The channel + * @blockheight: current blockheight + */ +void channel_update_blockheight(struct channel *channel, u32 blockheight); + /** * channel_feerate: Get fee rate for this side of channel. * @channel: The channel diff --git a/channeld/test/run-full_channel.c b/channeld/test/run-full_channel.c index e21350a6478b..5cb373c901bb 100644 --- a/channeld/test/run-full_channel.c +++ b/channeld/test/run-full_channel.c @@ -1,3 +1,4 @@ +#include "../../common/blockheight_states.c" #include "../../common/channel_id.c" #include "../../common/fee_states.c" #include "../../common/initial_channel.c" @@ -370,6 +371,7 @@ int main(int argc, const char *argv[]) const struct htlc **htlc_map, **htlcs; const u8 *funding_wscript, *funding_wscript_alt; bool option_anchor_outputs = false; + u32 blockheight = 0; size_t i; chainparams = chainparams_for_network("bitcoin"); @@ -481,6 +483,7 @@ int main(int argc, const char *argv[]) derive_channel_id(&cid, &funding_txid, funding_output_index); lchannel = new_full_channel(tmpctx, &cid, &funding_txid, funding_output_index, 0, + take(new_height_states(NULL, LOCAL, &blockheight)), 0, /* No channel lease */ funding_amount, to_local, take(new_fee_states(NULL, LOCAL, @@ -493,6 +496,7 @@ int main(int argc, const char *argv[]) false, false, LOCAL); rchannel = new_full_channel(tmpctx, &cid, &funding_txid, funding_output_index, 0, + take(new_height_states(NULL, LOCAL, &blockheight)), 0, /* No channel lease */ funding_amount, to_remote, take(new_fee_states(NULL, REMOTE, diff --git a/closingd/closingd_wiregen.c b/closingd/closingd_wiregen.c index d1a94dfb55f4..0fc850d97416 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:8a13df246be151bcef3dae15a9853016119248d330e76ab79d7013a11d5ecd23 +// SHA256STAMP:e1b60c5fe13077c645ab61650c9bd697148b169aa813f6f0053cf46783154260 diff --git a/closingd/closingd_wiregen.h b/closingd/closingd_wiregen.h index 9f46a12b97fe..f203da6cd0e6 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:8a13df246be151bcef3dae15a9853016119248d330e76ab79d7013a11d5ecd23 +// SHA256STAMP:e1b60c5fe13077c645ab61650c9bd697148b169aa813f6f0053cf46783154260 diff --git a/common/blockheight_states.c b/common/blockheight_states.c new file mode 100644 index 000000000000..3a5a151d13e2 --- /dev/null +++ b/common/blockheight_states.c @@ -0,0 +1,164 @@ +#include +#include +#include +#include +#include +#include +#include + +struct height_states *new_height_states(const tal_t *ctx, + enum side opener, + const u32 *blockheight) +{ + struct height_states *states = tal(ctx, struct height_states); + + /* Set to NULL except terminal value */ + for (size_t i = 0; i < ARRAY_SIZE(states->height); i++) + states->height[i] = NULL; + + if (blockheight) + /* We reuse fee states! */ + states->height[last_fee_state(opener)] + = tal_dup(states, u32, blockheight); + return states; +} + +u32 get_blockheight(const struct height_states *height_states, + enum side opener, + enum side side) +{ + /* The first non-NULL blockheight committed to this side is current */ + /* We use the same states as update_fee */ + for (enum htlc_state i = first_fee_state(opener); + i <= last_fee_state(opener); + i++) { + if (!height_states->height[i]) + continue; + if (!(htlc_state_flags(i) & HTLC_FLAG(side, HTLC_F_COMMITTED))) + continue; + return *height_states->height[i]; + } + + /* Some blockheight should always be set! */ + abort(); +} + +void start_height_update(struct height_states *height_states, + enum side opener, + u32 blockheight) +{ + /* Same as the feerate states */ + enum htlc_state start = first_fee_state(opener); + + /* BOLT #2: + * Unlike an HTLC, `update_fee` is never closed but simply replaced. + */ + if (height_states->height[start] == NULL) + height_states->height[start] = tal(height_states, u32); + *height_states->height[start] = blockheight; +} + + +/* Are blockheights all agreed by both sides? */ +bool blockheight_changes_done(const struct height_states *height_states, + bool ignore_uncommitted) +{ + size_t num_blockheights = 0; + for (size_t i = 0; i < ARRAY_SIZE(height_states->height); i++) { + if (ignore_uncommitted + && (i == RCVD_ADD_HTLC || i == SENT_ADD_HTLC)) + continue; + num_blockheights += (height_states->height[i] != NULL); + } + return num_blockheights == 1; +} + +bool inc_height_state(struct height_states *height_states, + enum htlc_state hstate) +{ + /* These only advance through ADDING states. */ + assert(htlc_state_flags(hstate) & HTLC_ADDING); + + if (!height_states->height[hstate]) + return false; + + /* FIXME: We can never clash, except at final state unless someone + * has violated protocol (eg, send two revoke_and_ack back-to-back) */ + tal_free(height_states->height[hstate+1]); + height_states->height[hstate+1] = height_states->height[hstate]; + height_states->height[hstate] = NULL; + return true; +} + +struct height_states *dup_height_states(const tal_t *ctx, + const struct height_states *states TAKES) +{ + struct height_states *n; + + if (taken(states)) + return cast_const(struct height_states *, + tal_steal(ctx, states)); + + n = tal_dup(ctx, struct height_states, states); + for (size_t i = 0; i < ARRAY_SIZE(n->height); i++) { + if (n->height[i]) + n->height[i] = tal_dup(n, u32, n->height[i]); + + } + return n; +} + +/* FIXME: we don't know opener inside fromwire_height_states, so can't do + * this there :( */ +bool height_states_valid(const struct height_states *states, enum side opener) +{ + /* We use the same states as update fee */ + return states->height[last_fee_state(opener)] != NULL; +} + +void towire_height_states(u8 **pptr, const struct height_states *states) +{ + for (enum htlc_state i = 0; i < ARRAY_SIZE(states->height); i++) { + /* We don't send uncommitted feestates */ + if (!(htlc_state_flags(i) & (HTLC_REMOTE_F_COMMITTED + | HTLC_LOCAL_F_COMMITTED)) + || states->height[i] == NULL) { + towire_bool(pptr, false); + continue; + } + towire_bool(pptr, true); + towire_u32(pptr, *states->height[i]); + } +} + +struct height_states *fromwire_height_states(const tal_t *ctx, const u8 **cursor, size_t *max) +{ + struct height_states *states = tal(ctx, struct height_states); + + for (enum htlc_state i = 0; i < ARRAY_SIZE(states->height); i++) { + if (fromwire_bool(cursor, max)) { + states->height[i] = tal(states, u32); + *states->height[i] = fromwire_u32(cursor, max); + } else { + states->height[i] = NULL; + } + } + if (!*cursor) + return tal_free(states); + return states; +} + +static const char *fmt_height_states(const tal_t *ctx, + const struct height_states *states) +{ + char *ret = tal_strdup(ctx, "{"); + for (enum htlc_state i = 0; i < ARRAY_SIZE(states->height); i++) { + if (states->height[i] != NULL) + tal_append_fmt(&ret, " %s:%u", + htlc_state_name(i), + *states->height[i]); + } + tal_append_fmt(&ret, " }"); + return ret; +} +REGISTER_TYPE_TO_STRING(height_states, fmt_height_states); diff --git a/common/blockheight_states.h b/common/blockheight_states.h new file mode 100644 index 000000000000..715517533a84 --- /dev/null +++ b/common/blockheight_states.h @@ -0,0 +1,79 @@ +#ifndef LIGHTNING_COMMON_BLOCKHEIGHT_STATES_H +#define LIGHTNING_COMMON_BLOCKHEIGHT_STATES_H +#include "config.h" +#include +#include + +struct height_states { + /* Current blockheight: goes through same + * state machine as feestate addition. + * + * We need to know if there's an actual change pending though (even if + * it's a "change" to an idential feerate!) so we use pointers. + */ + u32 *height[HTLC_STATE_INVALID]; +}; + +/** + * new_height_states: Initialize a height_states structure as at + * open-of-channel. + * @ctx: the tal ctx to allocate off + * @opener: which side opened the channel + * (and thus, proposes blockheight updates). + * @blockheight: the initial blockheight (if any). + */ +struct height_states *new_height_states(const tal_t *ctx, + enum side opener, + const u32 *blockheight); + +/** + * get_blockheight: Get the current blockheight + * @height_states: the blockheight state machine + * @opener: which side opened the channel + * (and thus, proposes blockheight updates). + * @side: which side to get the blockheight for + */ +u32 get_blockheight(const struct height_states *height_states, + enum side opener, + enum side side); + +/** + * start_height_update: feed a new blockheight update into state machine. + * @height_states: the height state machine + * @opener: which side opened the channel (and thus, proposes + * blockheight updates). + * @blockheight: the new blockheight. + */ +void start_height_update(struct height_states *height_states, + enum side opener, + u32 blockheight); +/** + * inc_height_state: move this blockheight to the next state. + * @height_states: the blockheight state machine + * @hstate: state + * + * Moves height_states[hstate] to height_states[hstate+1], if not NULL. + * Returns true if it wasn't NULL. + */ +bool inc_height_state(struct height_states *height_states, + enum htlc_state hstate); + +/* Are blockheights all agreed by both sides? */ +bool blockheight_changes_done(const struct height_states *height_states, + bool ignore_uncommitted); + +/* Duplicate a set of height states */ +struct height_states *dup_height_states(const tal_t *ctx, + const struct height_states *states TAKES); + +/* Marshal and unmarshal */ +void towire_height_states(u8 **pptr, const struct height_states *height_states); +/* FIXME: You must check that height_states_valid! */ +struct height_states *fromwire_height_states(const tal_t *ctx, + const u8 **cursor, size_t *max); + +/** + * is this height_state struct valid for this side? + */ +bool height_states_valid(const struct height_states *states, enum side opener); +#endif /* LIGHTNING_COMMON_BLOCKHEIGHT_STATES_H */ diff --git a/common/initial_channel.c b/common/initial_channel.c index b32c5bd9713c..b5c02767b6f8 100644 --- a/common/initial_channel.c +++ b/common/initial_channel.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,7 @@ struct channel *new_initial_channel(const tal_t *ctx, const struct bitcoin_txid *funding_txid, unsigned int funding_txout, u32 minimum_depth, + const struct height_states *height_states TAKES, u32 lease_expiry, struct amount_sat funding, struct amount_msat local_msatoshi, @@ -58,6 +60,9 @@ struct channel *new_initial_channel(const tal_t *ctx, /* takes() if necessary */ channel->fee_states = dup_fee_states(channel, fee_states); + /* takes() if necessary */ + channel->blockheight_states = dup_height_states(channel, height_states); + channel->view[LOCAL].owed[LOCAL] = channel->view[REMOTE].owed[LOCAL] = local_msatoshi; diff --git a/common/initial_channel.h b/common/initial_channel.h index 187286ff095f..959c66ba4368 100644 --- a/common/initial_channel.h +++ b/common/initial_channel.h @@ -62,6 +62,10 @@ struct channel { /* Fee changes, some which may be in transit */ struct fee_states *fee_states; + /* Blockheight changes, some which may be in transit + * (option_will_fund)*/ + struct height_states *blockheight_states; + /* What it looks like to each side. */ struct channel_view view[NUM_SIDES]; @@ -82,7 +86,8 @@ struct channel { * @funding_txid: The commitment transaction id. * @funding_txout: The commitment transaction output number. * @minimum_depth: The minimum confirmations needed for funding transaction. - * @lease_expiry: Block the lease expires + * @height_states: The blockheight update states. + * @lease_expiry: Block the lease expires. * @funding_satoshis: The commitment transaction amount. * @local_msatoshi: The amount for the local side (remainder goes to remote) * @fee_states: The fee update states. @@ -103,6 +108,7 @@ struct channel *new_initial_channel(const tal_t *ctx, const struct bitcoin_txid *funding_txid, unsigned int funding_txout, u32 minimum_depth, + const struct height_states *height_states TAKES, u32 lease_expiry, struct amount_sat funding, struct amount_msat local_msatoshi, diff --git a/common/peer_status_wiregen.c b/common/peer_status_wiregen.c index 0f12fa92a76f..3a0340416ad6 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:9d6739d97294bd0ec0691772616c4d3d0328d399ed2bef6c943f912aca7d438a +// SHA256STAMP:19118af89075707a68f9a89456d1bcf818da972931454dfa30700b769351e560 diff --git a/common/peer_status_wiregen.h b/common/peer_status_wiregen.h index 52d7941aecff..9f78de9bc966 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:9d6739d97294bd0ec0691772616c4d3d0328d399ed2bef6c943f912aca7d438a +// SHA256STAMP:19118af89075707a68f9a89456d1bcf818da972931454dfa30700b769351e560 diff --git a/common/status_wiregen.c b/common/status_wiregen.c index d97b9ee0f765..d8b3be818458 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:3164c82c28124ba916aebd075baa2315cd82cee0d785908da25c6aa6c5b11f22 +// SHA256STAMP:deb2f38c55e6ef91420aa811b86351d972576bfc47f02cfe3014c46fed5962c3 diff --git a/common/status_wiregen.h b/common/status_wiregen.h index 9a45697e02bc..c67bf81e1709 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:3164c82c28124ba916aebd075baa2315cd82cee0d785908da25c6aa6c5b11f22 +// SHA256STAMP:deb2f38c55e6ef91420aa811b86351d972576bfc47f02cfe3014c46fed5962c3 diff --git a/common/type_to_string.h b/common/type_to_string.h index e82dbd31b32c..fda0df7d106d 100644 --- a/common/type_to_string.h +++ b/common/type_to_string.h @@ -37,6 +37,7 @@ union printable_types { const struct amount_msat *amount_msat; const struct amount_sat *amount_sat; const struct fee_states *fee_states; + const struct height_states *height_states; const char *charp_; const struct wally_psbt *wally_psbt; const struct wally_tx *wally_tx; diff --git a/connectd/connectd_gossipd_wiregen.c b/connectd/connectd_gossipd_wiregen.c index ac2856c3abe5..89114222e106 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:6bfe0677cb910aba63f79cfc4164ce26034da95e16341eab3aac6fddcc04e3e9 +// SHA256STAMP:82c3831eab6ef72f96d6ab25b11861f33f3abea148d8739cd03bb8626678c84e diff --git a/connectd/connectd_gossipd_wiregen.h b/connectd/connectd_gossipd_wiregen.h index 5c391775adcd..d0cba543c711 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:6bfe0677cb910aba63f79cfc4164ce26034da95e16341eab3aac6fddcc04e3e9 +// SHA256STAMP:82c3831eab6ef72f96d6ab25b11861f33f3abea148d8739cd03bb8626678c84e diff --git a/connectd/connectd_wiregen.c b/connectd/connectd_wiregen.c index 3ee9ea506f2e..f4ab67805103 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:042c0ae692c223da86af3f09977fdc5f19655e99b928ab05812dd4c1ed95f1c5 +// SHA256STAMP:bb3410ed32fbe0fcb0246b4c00782bd6b4c63fb778cce28e40cfcb2ad579d65a diff --git a/connectd/connectd_wiregen.h b/connectd/connectd_wiregen.h index 34ad8ca34f41..5fa803707326 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:042c0ae692c223da86af3f09977fdc5f19655e99b928ab05812dd4c1ed95f1c5 +// SHA256STAMP:bb3410ed32fbe0fcb0246b4c00782bd6b4c63fb778cce28e40cfcb2ad579d65a diff --git a/devtools/Makefile b/devtools/Makefile index 247f853a3301..66c0ac681e63 100644 --- a/devtools/Makefile +++ b/devtools/Makefile @@ -18,6 +18,7 @@ DEVTOOLS_COMMON_OBJS := \ common/bech32_util.o \ common/bigsize.o \ common/bolt11.o \ + common/blockheight_states.o \ common/channel_id.o \ common/crypto_state.o \ common/decode_array.o \ diff --git a/devtools/mkcommit.c b/devtools/mkcommit.c index 8f0ba013a605..3abf94cf6f5b 100644 --- a/devtools/mkcommit.c +++ b/devtools/mkcommit.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -271,6 +272,7 @@ int main(int argc, char *argv[]) struct pubkey local_htlc_pubkey, remote_htlc_pubkey; bool option_static_remotekey = false, option_anchor_outputs = false; struct sha256_double hash; + u32 blockheight = 0; setup_locale(); chainparams = chainparams_for_network("bitcoin"); @@ -394,6 +396,8 @@ int main(int argc, char *argv[]) channel = new_full_channel(NULL, &cid, &funding_txid, funding_outnum, 1, + take(new_height_states(NULL, fee_payer, + &blockheight)), 0, /* Defaults to no lease */ funding_amount, local_msat, diff --git a/gossipd/gossip_store_wiregen.c b/gossipd/gossip_store_wiregen.c index 90cbd0b07a7b..bf8dc913ff5b 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:3e6e23b99855a3be9305cbc297d59d818cc193d6ebe5c2ca78dfb6ec5df31e94 +// SHA256STAMP:dd17fbe3d5e894679c6681818fb81b5407d19c8eb34d863aeda5cd46500bd956 diff --git a/gossipd/gossip_store_wiregen.h b/gossipd/gossip_store_wiregen.h index 0941d51e6151..4d1b612d6496 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:3e6e23b99855a3be9305cbc297d59d818cc193d6ebe5c2ca78dfb6ec5df31e94 +// SHA256STAMP:dd17fbe3d5e894679c6681818fb81b5407d19c8eb34d863aeda5cd46500bd956 diff --git a/gossipd/gossipd_peerd_wiregen.c b/gossipd/gossipd_peerd_wiregen.c index a6ff50636ec1..1ca000e06071 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:e55284452718ed1baf12a38736b4bfeecc8bb18dac8ad4f0ee0b5dc8904fbdc2 +// SHA256STAMP:844e57181b9d9fae198f9eb0c4de8d9742a03194eea89058641c24670a5fb935 diff --git a/gossipd/gossipd_peerd_wiregen.h b/gossipd/gossipd_peerd_wiregen.h index 8240e6616c78..ebc9d57fbbac 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:e55284452718ed1baf12a38736b4bfeecc8bb18dac8ad4f0ee0b5dc8904fbdc2 +// SHA256STAMP:844e57181b9d9fae198f9eb0c4de8d9742a03194eea89058641c24670a5fb935 diff --git a/gossipd/gossipd_wiregen.c b/gossipd/gossipd_wiregen.c index 51ce056d1214..3237473361b9 100644 --- a/gossipd/gossipd_wiregen.c +++ b/gossipd/gossipd_wiregen.c @@ -1081,4 +1081,4 @@ bool fromwire_gossipd_new_lease_rates(const void *p, struct lease_rates *rates) fromwire_lease_rates(&cursor, &plen, rates); return cursor != NULL; } -// SHA256STAMP:a9b05ef5740445f1074c703bb85758e50286d48fc21e723d40f61d3febd9df12 +// SHA256STAMP:85cc676dac833ef56e79962024738ff836a924e8d2dcbdd9557eb21c86ffd3dd diff --git a/gossipd/gossipd_wiregen.h b/gossipd/gossipd_wiregen.h index 64ad7ee9e3cd..2ab53ad7162a 100644 --- a/gossipd/gossipd_wiregen.h +++ b/gossipd/gossipd_wiregen.h @@ -233,4 +233,4 @@ bool fromwire_gossipd_new_lease_rates(const void *p, struct lease_rates *rates); #endif /* LIGHTNING_GOSSIPD_GOSSIPD_WIREGEN_H */ -// SHA256STAMP:a9b05ef5740445f1074c703bb85758e50286d48fc21e723d40f61d3febd9df12 +// SHA256STAMP:85cc676dac833ef56e79962024738ff836a924e8d2dcbdd9557eb21c86ffd3dd diff --git a/hsmd/hsmd_wiregen.c b/hsmd/hsmd_wiregen.c index 0007219f96e7..2263247658ed 100644 --- a/hsmd/hsmd_wiregen.c +++ b/hsmd/hsmd_wiregen.c @@ -1331,4 +1331,4 @@ bool fromwire_hsmd_sign_option_will_fund_offer_reply(const void *p, secp256k1_ec fromwire_secp256k1_ecdsa_signature(&cursor, &plen, rsig); return cursor != NULL; } -// SHA256STAMP:3096344d3102d59f92c00038c3ee948221f80969db85c305f7c15772a7f46593 +// SHA256STAMP:db96cc713b36122efe50406d2c99a1f9e4a9b3663107196f1776e9a299d224a2 diff --git a/hsmd/hsmd_wiregen.h b/hsmd/hsmd_wiregen.h index 1623d611e49a..7ce15d540619 100644 --- a/hsmd/hsmd_wiregen.h +++ b/hsmd/hsmd_wiregen.h @@ -295,4 +295,4 @@ bool fromwire_hsmd_sign_option_will_fund_offer_reply(const void *p, secp256k1_ec #endif /* LIGHTNING_HSMD_HSMD_WIREGEN_H */ -// SHA256STAMP:3096344d3102d59f92c00038c3ee948221f80969db85c305f7c15772a7f46593 +// SHA256STAMP:db96cc713b36122efe50406d2c99a1f9e4a9b3663107196f1776e9a299d224a2 diff --git a/lightningd/Makefile b/lightningd/Makefile index 117ccf2250e1..c4dfafdd315f 100644 --- a/lightningd/Makefile +++ b/lightningd/Makefile @@ -69,6 +69,7 @@ LIGHTNINGD_COMMON_OBJS := \ common/bigsize.o \ common/bip32.o \ common/blinding.o \ + common/blockheight_states.o \ common/bolt11.o \ common/bolt11_json.o \ common/bolt12.o \ diff --git a/lightningd/channel.c b/lightningd/channel.c index 1a5d2ee1d879..a4ead163d169 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -163,8 +164,8 @@ new_inflight(struct channel *channel, const struct bitcoin_signature last_sig, const u32 lease_expiry, const secp256k1_ecdsa_signature *lease_commit_sig, - const u32 lease_chan_max_msat, - const u16 lease_chan_max_ppt) + const u32 lease_chan_max_msat, const u16 lease_chan_max_ppt, + const u32 lease_blockheight_start) { struct wally_psbt *last_tx_psbt_clone; struct channel_inflight *inflight @@ -189,8 +190,16 @@ new_inflight(struct channel *channel, inflight->last_sig = last_sig; inflight->tx_broadcast = false; + /* Channel lease infos */ + inflight->lease_blockheight_start = lease_blockheight_start; inflight->lease_expiry = lease_expiry; - inflight->lease_commit_sig = tal_dup(inflight, secp256k1_ecdsa_signature, lease_commit_sig); + if (lease_commit_sig) + inflight->lease_commit_sig + = tal_dup(inflight, secp256k1_ecdsa_signature, + lease_commit_sig); + else + inflight->lease_commit_sig = NULL; + inflight->lease_chan_max_msat = lease_chan_max_msat; inflight->lease_chan_max_ppt = lease_chan_max_ppt; @@ -353,6 +362,7 @@ struct channel *new_channel(struct peer *peer, u64 dbid, enum state_change reason, /* NULL or stolen */ const struct bitcoin_outpoint *shutdown_wrong_funding, + const struct height_states *height_states TAKES, u32 lease_expiry, secp256k1_ecdsa_signature *lease_commit_sig STEALS, u32 lease_chan_max_msat, @@ -449,6 +459,7 @@ struct channel *new_channel(struct peer *peer, u64 dbid, channel->lease_commit_sig = tal_steal(channel, lease_commit_sig); channel->lease_chan_max_msat = lease_chan_max_msat; channel->lease_chan_max_ppt = lease_chan_max_ppt; + channel->blockheight_states = dup_height_states(channel, height_states); list_add_tail(&peer->channels, &channel->list); channel->rr_number = peer->ld->rr_counter++; diff --git a/lightningd/channel.h b/lightningd/channel.h index 36c070ab3bfe..1c25702ed800 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -51,6 +51,7 @@ struct channel_inflight { secp256k1_ecdsa_signature *lease_commit_sig; u32 lease_chan_max_msat; u16 lease_chan_max_ppt; + u32 lease_blockheight_start; }; struct open_attempt { @@ -150,6 +151,9 @@ struct channel { /* Fee status */ const struct fee_states *fee_states; + /* Height states (option_will_fund, update_blockheight) */ + const struct height_states *blockheight_states; + /* Our local basepoints */ struct basepoints local_basepoints; @@ -292,6 +296,7 @@ struct channel *new_channel(struct peer *peer, u64 dbid, enum state_change reason, /* NULL or stolen */ const struct bitcoin_outpoint *shutdown_wrong_funding STEALS, + const struct height_states *height_states TAKES, u32 lease_expiry, secp256k1_ecdsa_signature *lease_commit_sig STEALS, u32 lease_chan_max_msat, @@ -311,7 +316,8 @@ new_inflight(struct channel *channel, const u32 lease_expiry, const secp256k1_ecdsa_signature *lease_commit_sig, const u32 lease_chan_max_msat, - const u16 lease_chan_max_ppt); + const u16 lease_chan_max_ppt, + const u32 lease_blockheight_start); /* Given a txid, find an inflight channel stub. Returns NULL if none found */ struct channel_inflight *channel_inflight_find(struct channel *channel, diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index e8c87401af1d..36db119faa8d 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -69,6 +69,30 @@ static void try_update_feerates(struct lightningd *ld, struct channel *channel) update_feerates(ld, channel); } +static void try_update_blockheight(struct lightningd *ld, + struct channel *channel, + u32 blockheight) +{ + u8 *msg; + + /* We use the same heuristic for channel states as feerates */ + if (!channel_fees_can_change(channel)) + return; + + /* Can't if no daemon listening. */ + if (!channel->owner) + return; + + /* We don't update the blockheight for non-leased chans */ + if (channel->lease_expiry == 0) + return; + + log_debug(ld->log, "update_blockheight: height = %u", blockheight); + + msg = towire_channeld_blockheight(NULL, blockheight); + subd_send_msg(channel->owner, take(msg)); +} + void notify_feerate_change(struct lightningd *ld) { struct peer *peer; @@ -155,6 +179,9 @@ static void lockin_complete(struct channel *channel) /* Fees might have changed (and we use IMMEDIATE once we're funded), * so update now. */ try_update_feerates(channel->peer->ld, channel); + + try_update_blockheight(channel->peer->ld, channel, + get_block_height(channel->peer->ld->topology)); channel_record_open(channel); } @@ -447,6 +474,7 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds) case WIRE_CHANNELD_SEND_SHUTDOWN: case WIRE_CHANNELD_DEV_REENABLE_COMMIT: case WIRE_CHANNELD_FEERATES: + case WIRE_CHANNELD_BLOCKHEIGHT: case WIRE_CHANNELD_SPECIFIC_FEERATES: case WIRE_CHANNELD_DEV_MEMLEAK: case WIRE_CHANNELD_DEV_QUIESCE: @@ -586,6 +614,9 @@ void peer_start_channeld(struct channel *channel, channel->funding_outnum, channel->funding, channel->minimum_depth, + get_block_height(ld->topology), + channel->blockheight_states, + channel->lease_expiry, &channel->our_config, &channel->channel_info.their_config, channel->fee_states, @@ -641,9 +672,13 @@ void peer_start_channeld(struct channel *channel, /* We don't expect a response: we are triggered by funding_depth_cb. */ subd_send_msg(channel->owner, take(initmsg)); - /* On restart, feerate might not be what we expect: adjust now. */ - if (channel->opener == LOCAL) + /* On restart, feerate and blockheight + * might not be what we expect: adjust now. */ + if (channel->opener == LOCAL) { try_update_feerates(ld, channel); + try_update_blockheight(ld, channel, + get_block_height(ld->topology)); + } } bool channel_tell_depth(struct lightningd *ld, @@ -751,7 +786,11 @@ void channel_notify_new_block(struct lightningd *ld, continue; if (is_fundee_should_forget(ld, channel, block_height)) { tal_arr_expand(&to_forget, channel); - } + } else + /* Let channels know about new blocks, + * required for lease updates */ + try_update_blockheight(ld, channel, + block_height); } } diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index cb655cf734c4..ab653e1a2ad3 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -1116,7 +1117,8 @@ wallet_update_channel(struct lightningd *ld, const u32 lease_expiry, secp256k1_ecdsa_signature *lease_commit_sig STEALS, const u32 lease_chan_max_msat, - const u16 lease_chan_max_ppt) + const u16 lease_chan_max_ppt, + const u32 lease_blockheight_start) { struct amount_msat our_msat; struct channel_inflight *inflight; @@ -1143,6 +1145,11 @@ wallet_update_channel(struct lightningd *ld, channel->lease_chan_max_msat = lease_chan_max_msat; channel->lease_chan_max_ppt = lease_chan_max_ppt; + tal_free(channel->blockheight_states); + channel->blockheight_states = new_height_states(channel, + channel->opener, + &lease_blockheight_start); + channel_set_last_tx(channel, tal_steal(channel, remote_commit), remote_commit_sig, @@ -1164,7 +1171,8 @@ wallet_update_channel(struct lightningd *ld, channel->lease_expiry, channel->lease_commit_sig, channel->lease_chan_max_msat, - channel->lease_chan_max_ppt); + channel->lease_chan_max_ppt, + lease_blockheight_start); wallet_inflight_add(ld->wallet, inflight); return inflight; @@ -1186,6 +1194,7 @@ wallet_commit_channel(struct lightningd *ld, const u8 *our_upfront_shutdown_script, const u8 *remote_upfront_shutdown_script, struct wally_psbt *psbt STEALS, + const u32 lease_blockheight_start, const u32 lease_expiry, secp256k1_ecdsa_signature *lease_commit_sig STEALS, const u32 lease_chan_max_msat, @@ -1257,6 +1266,9 @@ wallet_commit_channel(struct lightningd *ld, channel->first_blocknum = get_block_height(ld->topology); /* Update lease info for channel */ + channel->blockheight_states = new_height_states(channel, + channel->opener, + &lease_blockheight_start); channel->lease_expiry = lease_expiry; tal_free(channel->lease_commit_sig); @@ -1281,7 +1293,8 @@ wallet_commit_channel(struct lightningd *ld, channel->lease_expiry, channel->lease_commit_sig, channel->lease_chan_max_msat, - channel->lease_chan_max_ppt); + channel->lease_chan_max_ppt, + lease_blockheight_start); wallet_inflight_add(ld->wallet, inflight); return inflight; @@ -2818,7 +2831,7 @@ static void handle_commit_received(struct subd *dualopend, struct bitcoin_txid funding_txid; u16 funding_outnum, lease_chan_max_ppt; u32 feerate_funding, feerate_commitment, lease_expiry, - lease_chan_max_msat; + lease_chan_max_msat, lease_blockheight_start; struct amount_sat total_funding, funding_ours; u8 *remote_upfront_shutdown_script, *local_upfront_shutdown_script; @@ -2851,6 +2864,7 @@ static void handle_commit_received(struct subd *dualopend, &feerate_commitment, &local_upfront_shutdown_script, &remote_upfront_shutdown_script, + &lease_blockheight_start, &lease_expiry, &lease_commit_sig, &lease_chan_max_msat, @@ -2896,6 +2910,7 @@ static void handle_commit_received(struct subd *dualopend, local_upfront_shutdown_script, remote_upfront_shutdown_script, psbt, + lease_blockheight_start, lease_expiry, lease_commit_sig, lease_chan_max_msat, @@ -2932,7 +2947,8 @@ static void handle_commit_received(struct subd *dualopend, lease_expiry, lease_commit_sig, lease_chan_max_msat, - lease_chan_max_ppt))) { + lease_chan_max_ppt, + lease_blockheight_start))) { channel_internal_error(channel, "wallet_update_channel failed" " (chan %s)", @@ -3209,7 +3225,7 @@ void peer_restart_dualopend(struct peer *peer, struct per_peer_state *pps, struct channel *channel) { - u32 max_to_self_delay; + u32 max_to_self_delay, blockheight; struct amount_msat min_effective_htlc_capacity; struct channel_config unused_config; struct channel_inflight *inflight, *first_inflight; @@ -3253,6 +3269,8 @@ void peer_restart_dualopend(struct peer *peer, inflight = channel_current_inflight(channel); assert(inflight); + blockheight = get_blockheight(channel->blockheight_states, + channel->opener, LOCAL); /* Get the first inflight to figure out the original feerate * for this channel. It's fine if it's the same as the current */ @@ -3293,6 +3311,7 @@ void peer_restart_dualopend(struct peer *peer, inflight->remote_tx_sigs, channel->fee_states, channel->channel_flags, + blockheight, inflight->lease_expiry, inflight->lease_commit_sig, inflight->lease_chan_max_msat, diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index b17060a8fad3..edba50d8462d 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -105,6 +106,7 @@ wallet_commit_channel(struct lightningd *ld, s64 final_key_idx; u64 static_remotekey_start; bool option_anchor_outputs; + u32 lease_start_blockheight = 0; /* No leases on v1 */ /* We cannot both be the fundee *and* have a `fundchannel_start` * command running! @@ -217,6 +219,8 @@ wallet_commit_channel(struct lightningd *ld, NUM_SIDES, /* closer not yet known */ uc->fc ? REASON_USER : REASON_REMOTE, NULL, + take(new_height_states(NULL, uc->fc ? LOCAL : REMOTE, + &lease_start_blockheight)), 0, NULL, 0, 0); /* No leases on v1s */ /* Now we finally put it in the database. */ diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index f7294b843136..7aa8cdd9c5c7 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -1345,6 +1345,11 @@ static void update_channel_from_inflight(struct lightningd *ld, channel->lease_chan_max_msat = inflight->lease_chan_max_msat; channel->lease_chan_max_ppt = inflight->lease_chan_max_ppt; + tal_free(channel->blockheight_states); + channel->blockheight_states = new_height_states(channel, + channel->opener, + &inflight->lease_blockheight_start); + /* Make a 'clone' of this tx */ psbt_copy = clone_psbt(channel, inflight->last_tx->psbt); channel_set_last_tx(channel, diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index 8709fb588644..409038e56331 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -423,6 +423,11 @@ void merkle_tlv(const struct tlv_field *fields UNNEEDED, struct sha256 *merkle U struct bolt11 *new_bolt11(const tal_t *ctx UNNEEDED, const struct amount_msat *msat TAKES UNNEEDED) { fprintf(stderr, "new_bolt11 called!\n"); abort(); } +/* Generated stub for new_height_states */ +struct height_states *new_height_states(const tal_t *ctx UNNEEDED, + enum side opener UNNEEDED, + const u32 *blockheight UNNEEDED) +{ fprintf(stderr, "new_height_states called!\n"); abort(); } /* Generated stub for new_reltimer_ */ struct oneshot *new_reltimer_(struct timers *timers UNNEEDED, const tal_t *ctx UNNEEDED, diff --git a/onchaind/onchaind_wiregen.c b/onchaind/onchaind_wiregen.c index 381c0376cdd6..6a32dabaec5f 100644 --- a/onchaind/onchaind_wiregen.c +++ b/onchaind/onchaind_wiregen.c @@ -637,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:66e19538be7f5a9e9076bfe995a9bf0cbb5d303df8f6c383e427c11ef2e85e2e +// SHA256STAMP:08b8cb168df5294bb10d79d57cbefaa80072efcda5bf13b7f3469506623205bb diff --git a/onchaind/onchaind_wiregen.h b/onchaind/onchaind_wiregen.h index 48692bae739b..57e38a93f03c 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:66e19538be7f5a9e9076bfe995a9bf0cbb5d303df8f6c383e427c11ef2e85e2e +// SHA256STAMP:08b8cb168df5294bb10d79d57cbefaa80072efcda5bf13b7f3469506623205bb diff --git a/openingd/Makefile b/openingd/Makefile index 98b176ec07b5..655119611f5c 100644 --- a/openingd/Makefile +++ b/openingd/Makefile @@ -36,6 +36,7 @@ OPENINGD_COMMON_OBJS := \ common/bigsize.o \ common/billboard.o \ common/bip32.o \ + common/blockheight_states.o \ common/channel_config.o \ common/channel_id.o \ common/crypto_state.o \ diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 9b0a4da1a299..0e6dfc950777 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -124,6 +125,9 @@ struct tx_state { /* Rates that we're using for this open... */ struct lease_rates *rates; + /* Lease blockheight start */ + u32 blockheight; + /* If delay til the channel funds lease expires */ u32 lease_expiry; @@ -144,6 +148,7 @@ static struct tx_state *new_tx_state(const tal_t *ctx) tx_state->remote_funding_sigs_rcvd = false; tx_state->lease_expiry = 0; + tx_state->blockheight = 0; tx_state->lease_commit_sig = NULL; tx_state->lease_chan_max_msat = 0; tx_state->lease_chan_max_ppt = 0; @@ -1672,6 +1677,8 @@ static void revert_channel_state(struct state *state) &tx_state->funding_txid, tx_state->funding_txout, state->minimum_depth, + take(new_height_states(NULL, opener, + &tx_state->blockheight)), tx_state->lease_expiry, total, our_msats, @@ -1771,6 +1778,9 @@ static u8 *accepter_commits(struct state *state, &tx_state->funding_txid, tx_state->funding_txout, state->minimum_depth, + take(new_height_states(NULL, REMOTE, + &tx_state->blockheight)), + tx_state->lease_expiry, total, our_msats, @@ -1897,6 +1907,7 @@ static u8 *accepter_commits(struct state *state, state->feerate_per_kw_commitment, state->upfront_shutdown_script[LOCAL], state->upfront_shutdown_script[REMOTE], + tx_state->blockheight, tx_state->lease_expiry, tx_state->lease_commit_sig, tx_state->lease_chan_max_msat, @@ -1978,7 +1989,6 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) char *err_reason; u8 *msg; struct amount_sat total, requested_amt, lease_fee; - u32 lease_blockheight_start; enum dualopend_wire msg_type; struct tx_state *tx_state = state->tx_state; @@ -2018,12 +2028,10 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) /* FIXME: Do we support this? */ requested_amt = amount_sat(open_tlv->request_funds->requested_sats); - lease_blockheight_start + tx_state->blockheight = open_tlv->request_funds->blockheight; - } else { + } else requested_amt = AMOUNT_SAT(0); - lease_blockheight_start = 0; - } /* BOLT-* #2 * If the peer's revocation basepoint is unknown (e.g. @@ -2093,7 +2101,7 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) tx_state->tx_locktime, state->upfront_shutdown_script[REMOTE], requested_amt, - lease_blockheight_start); + tx_state->blockheight); wire_sync_write(REQ_FD, take(msg)); msg = wire_sync_read(tmpctx, REQ_FD); @@ -2206,7 +2214,7 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) if (open_tlv->request_funds && tx_state->rates) accept_tlv_add_offer(a_tlv, tx_state, tx_state->rates, state->our_funding_pubkey, - lease_blockheight_start); + tx_state->blockheight); msg = towire_accept_channel2(tmpctx, &state->channel_id, @@ -2236,7 +2244,7 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) /* Add our fee to our amount now */ if (tx_state->rates) { tx_state->lease_expiry - = lease_blockheight_start + LEASE_RATE_DURATION; + = tx_state->blockheight + LEASE_RATE_DURATION; /* BOLT- #2: * The lease fee is added to the accepter's balance @@ -2380,6 +2388,8 @@ static u8 *opener_commits(struct state *state, &tx_state->funding_txid, tx_state->funding_txout, state->minimum_depth, + take(new_height_states(NULL, LOCAL, + &state->tx_state->blockheight)), tx_state->lease_expiry, total, our_msats, @@ -2550,6 +2560,7 @@ static u8 *opener_commits(struct state *state, state->feerate_per_kw_commitment, state->upfront_shutdown_script[LOCAL], state->upfront_shutdown_script[REMOTE], + tx_state->blockheight, tx_state->lease_expiry, tx_state->lease_commit_sig, tx_state->lease_chan_max_msat, @@ -2564,7 +2575,6 @@ static void opener_start(struct state *state, u8 *msg) struct channel_id cid; char *err_reason; struct amount_sat total, requested_sats, lease_fee; - u32 current_blockheight; bool dry_run; struct tx_state *tx_state = state->tx_state; @@ -2576,7 +2586,7 @@ static void opener_start(struct state *state, u8 *msg) &state->feerate_per_kw_funding, &state->channel_flags, &requested_sats, - ¤t_blockheight, + &tx_state->blockheight, &dry_run)) master_badmsg(WIRE_DUALOPEND_OPENER_INIT, msg); @@ -2612,7 +2622,7 @@ static void opener_start(struct state *state, u8 *msg) tal(open_tlv, struct tlv_opening_tlvs_request_funds); open_tlv->request_funds->requested_sats = requested_sats.satoshis; /* Raw: struct -> wire */ - open_tlv->request_funds->blockheight = current_blockheight; + open_tlv->request_funds->blockheight = tx_state->blockheight; } msg = towire_open_channel2(NULL, @@ -2725,7 +2735,7 @@ static void opener_start(struct state *state, u8 *msg) char *err_msg; struct lease_rates *rates = &a_tlv->will_fund->lease_rates; - tx_state->lease_expiry = current_blockheight + LEASE_RATE_DURATION; + tx_state->lease_expiry = tx_state->blockheight + LEASE_RATE_DURATION; msg = towire_dualopend_validate_lease(NULL, &a_tlv->will_fund->signature, @@ -3798,6 +3808,7 @@ int main(int argc, char *argv[]) &state->tx_state->remote_funding_sigs_rcvd, &fee_states, &state->channel_flags, + &state->tx_state->blockheight, &state->tx_state->lease_expiry, &state->tx_state->lease_commit_sig, &state->tx_state->lease_chan_max_msat, @@ -3810,6 +3821,8 @@ int main(int argc, char *argv[]) &state->tx_state->funding_txid, state->tx_state->funding_txout, state->minimum_depth, + take(new_height_states(NULL, opener, + &state->tx_state->blockheight)), state->tx_state->lease_expiry, total_funding, our_msat, diff --git a/openingd/dualopend_wire.csv b/openingd/dualopend_wire.csv index 82d88173c064..9b1e88c577b1 100644 --- a/openingd/dualopend_wire.csv +++ b/openingd/dualopend_wire.csv @@ -66,6 +66,7 @@ msgdata,dualopend_reinit,remote_shutdown_scriptpubkey,u8,remote_shutdown_len msgdata,dualopend_reinit,remote_funding_sigs_received,bool, msgdata,dualopend_reinit,fee_states,fee_states, msgdata,dualopend_reinit,channel_flags,u8, +msgdata,dualopend_reinit,lease_start_blockheight,u32, msgdata,dualopend_reinit,lease_expiry,u32, msgdata,dualopend_reinit,lease_commit_sig,?secp256k1_ecdsa_signature, msgdata,dualopend_reinit,lease_chan_max_msat,u32, @@ -146,6 +147,7 @@ msgdata,dualopend_commit_rcvd,local_shutdown_len,u16, msgdata,dualopend_commit_rcvd,local_shutdown_scriptpubkey,u8,local_shutdown_len msgdata,dualopend_commit_rcvd,remote_shutdown_len,u16, msgdata,dualopend_commit_rcvd,remote_shutdown_scriptpubkey,u8,remote_shutdown_len +msgdata,dualopend_commit_rcvd,lease_start_blockheight,u32, msgdata,dualopend_commit_rcvd,lease_expiry,u32, msgdata,dualopend_commit_rcvd,lease_commit_sig,?secp256k1_ecdsa_signature, msgdata,dualopend_commit_rcvd,lease_chan_max_msat,u32, diff --git a/openingd/dualopend_wiregen.c b/openingd/dualopend_wiregen.c index 5f94893b664e..bfc8d745669f 100644 --- a/openingd/dualopend_wiregen.c +++ b/openingd/dualopend_wiregen.c @@ -152,7 +152,7 @@ bool fromwire_dualopend_init(const tal_t *ctx, const void *p, const struct chain /* WIRE: DUALOPEND_REINIT */ /* master-dualopend: peer has reconnected */ -u8 *towire_dualopend_reinit(const tal_t *ctx, const struct chainparams *chainparams, const struct feature_set *our_feature_set, const u8 *their_init_features, const struct channel_config *our_config, const struct channel_config *their_config, const struct channel_id *channel_id, u32 max_to_self_delay, struct amount_msat min_effective_htlc_capacity_msat, const struct per_peer_state *pps, const struct basepoints *our_basepoints, const struct pubkey *our_funding_pubkey, const struct pubkey *their_funding_pubkey, u32 minimum_depth, const struct bitcoin_txid *funding_txid, u16 funding_txout, u32 orignal_feerate_per_kw_funding, u32 most_recent_feerate_per_kw_funding, struct amount_sat funding_satoshi, struct amount_msat our_funding, const struct basepoints *their_basepoints, const struct pubkey *remote_per_commit, const struct wally_psbt *funding_psbt, enum side opener, bool local_funding_locked, bool remote_funding_locked, bool send_shutdown, bool remote_shutdown_received, const u8 *local_shutdown_scriptpubkey, const u8 *remote_shutdown_scriptpubkey, bool remote_funding_sigs_received, const struct fee_states *fee_states, u8 channel_flags, u32 lease_expiry, const secp256k1_ecdsa_signature *lease_commit_sig, u32 lease_chan_max_msat, u16 lease_chan_max_ppt) +u8 *towire_dualopend_reinit(const tal_t *ctx, const struct chainparams *chainparams, const struct feature_set *our_feature_set, const u8 *their_init_features, const struct channel_config *our_config, const struct channel_config *their_config, const struct channel_id *channel_id, u32 max_to_self_delay, struct amount_msat min_effective_htlc_capacity_msat, const struct per_peer_state *pps, const struct basepoints *our_basepoints, const struct pubkey *our_funding_pubkey, const struct pubkey *their_funding_pubkey, u32 minimum_depth, const struct bitcoin_txid *funding_txid, u16 funding_txout, u32 orignal_feerate_per_kw_funding, u32 most_recent_feerate_per_kw_funding, struct amount_sat funding_satoshi, struct amount_msat our_funding, const struct basepoints *their_basepoints, const struct pubkey *remote_per_commit, const struct wally_psbt *funding_psbt, enum side opener, bool local_funding_locked, bool remote_funding_locked, bool send_shutdown, bool remote_shutdown_received, const u8 *local_shutdown_scriptpubkey, const u8 *remote_shutdown_scriptpubkey, bool remote_funding_sigs_received, const struct fee_states *fee_states, u8 channel_flags, u32 lease_start_blockheight, u32 lease_expiry, const secp256k1_ecdsa_signature *lease_commit_sig, u32 lease_chan_max_msat, u16 lease_chan_max_ppt) { u16 their_init_features_len = tal_count(their_init_features); u16 local_shutdown_len = tal_count(local_shutdown_scriptpubkey); @@ -195,6 +195,7 @@ u8 *towire_dualopend_reinit(const tal_t *ctx, const struct chainparams *chainpar towire_bool(&p, remote_funding_sigs_received); towire_fee_states(&p, fee_states); towire_u8(&p, channel_flags); + towire_u32(&p, lease_start_blockheight); towire_u32(&p, lease_expiry); if (!lease_commit_sig) towire_bool(&p, false); @@ -207,7 +208,7 @@ u8 *towire_dualopend_reinit(const tal_t *ctx, const struct chainparams *chainpar return memcheck(p, tal_count(p)); } -bool fromwire_dualopend_reinit(const tal_t *ctx, const void *p, const struct chainparams **chainparams, struct feature_set **our_feature_set, u8 **their_init_features, struct channel_config *our_config, struct channel_config *their_config, struct channel_id *channel_id, u32 *max_to_self_delay, struct amount_msat *min_effective_htlc_capacity_msat, struct per_peer_state **pps, struct basepoints *our_basepoints, struct pubkey *our_funding_pubkey, struct pubkey *their_funding_pubkey, u32 *minimum_depth, struct bitcoin_txid *funding_txid, u16 *funding_txout, u32 *orignal_feerate_per_kw_funding, u32 *most_recent_feerate_per_kw_funding, struct amount_sat *funding_satoshi, struct amount_msat *our_funding, struct basepoints *their_basepoints, struct pubkey *remote_per_commit, struct wally_psbt **funding_psbt, enum side *opener, bool *local_funding_locked, bool *remote_funding_locked, bool *send_shutdown, bool *remote_shutdown_received, u8 **local_shutdown_scriptpubkey, u8 **remote_shutdown_scriptpubkey, bool *remote_funding_sigs_received, struct fee_states **fee_states, u8 *channel_flags, u32 *lease_expiry, secp256k1_ecdsa_signature **lease_commit_sig, u32 *lease_chan_max_msat, u16 *lease_chan_max_ppt) +bool fromwire_dualopend_reinit(const tal_t *ctx, const void *p, const struct chainparams **chainparams, struct feature_set **our_feature_set, u8 **their_init_features, struct channel_config *our_config, struct channel_config *their_config, struct channel_id *channel_id, u32 *max_to_self_delay, struct amount_msat *min_effective_htlc_capacity_msat, struct per_peer_state **pps, struct basepoints *our_basepoints, struct pubkey *our_funding_pubkey, struct pubkey *their_funding_pubkey, u32 *minimum_depth, struct bitcoin_txid *funding_txid, u16 *funding_txout, u32 *orignal_feerate_per_kw_funding, u32 *most_recent_feerate_per_kw_funding, struct amount_sat *funding_satoshi, struct amount_msat *our_funding, struct basepoints *their_basepoints, struct pubkey *remote_per_commit, struct wally_psbt **funding_psbt, enum side *opener, bool *local_funding_locked, bool *remote_funding_locked, bool *send_shutdown, bool *remote_shutdown_received, u8 **local_shutdown_scriptpubkey, u8 **remote_shutdown_scriptpubkey, bool *remote_funding_sigs_received, struct fee_states **fee_states, u8 *channel_flags, u32 *lease_start_blockheight, u32 *lease_expiry, secp256k1_ecdsa_signature **lease_commit_sig, u32 *lease_chan_max_msat, u16 *lease_chan_max_ppt) { u16 their_init_features_len; u16 local_shutdown_len; @@ -259,6 +260,7 @@ bool fromwire_dualopend_reinit(const tal_t *ctx, const void *p, const struct cha *remote_funding_sigs_received = fromwire_bool(&cursor, &plen); *fee_states = fromwire_fee_states(ctx, &cursor, &plen); *channel_flags = fromwire_u8(&cursor, &plen); + *lease_start_blockheight = fromwire_u32(&cursor, &plen); *lease_expiry = fromwire_u32(&cursor, &plen); if (!fromwire_bool(&cursor, &plen)) *lease_commit_sig = NULL; @@ -492,7 +494,7 @@ bool fromwire_dualopend_rbf_init(const tal_t *ctx, const void *p, struct amount_ /* WIRE: DUALOPEND_COMMIT_RCVD */ /* dualopend->master: ready to commit channel open to database and */ /* get some signatures for the funding_tx. */ -u8 *towire_dualopend_commit_rcvd(const tal_t *ctx, const struct channel_config *their_config, const struct bitcoin_tx *remote_first_commit, const struct penalty_base *pbase, const struct bitcoin_signature *first_commit_sig, const struct wally_psbt *psbt, const struct pubkey *revocation_basepoint, const struct pubkey *payment_basepoint, const struct pubkey *htlc_basepoint, const struct pubkey *delayed_payment_basepoint, const struct pubkey *their_per_commit_point, const struct pubkey *remote_fundingkey, const struct bitcoin_txid *funding_txid, u16 funding_txout, struct amount_sat funding_satoshis, struct amount_sat our_funding_sats, u8 channel_flags, u32 feerate_per_kw_funding, u32 feerate_per_kw_commitment, const u8 *local_shutdown_scriptpubkey, const u8 *remote_shutdown_scriptpubkey, u32 lease_expiry, const secp256k1_ecdsa_signature *lease_commit_sig, u32 lease_chan_max_msat, u16 lease_chan_max_ppt) +u8 *towire_dualopend_commit_rcvd(const tal_t *ctx, const struct channel_config *their_config, const struct bitcoin_tx *remote_first_commit, const struct penalty_base *pbase, const struct bitcoin_signature *first_commit_sig, const struct wally_psbt *psbt, const struct pubkey *revocation_basepoint, const struct pubkey *payment_basepoint, const struct pubkey *htlc_basepoint, const struct pubkey *delayed_payment_basepoint, const struct pubkey *their_per_commit_point, const struct pubkey *remote_fundingkey, const struct bitcoin_txid *funding_txid, u16 funding_txout, struct amount_sat funding_satoshis, struct amount_sat our_funding_sats, u8 channel_flags, u32 feerate_per_kw_funding, u32 feerate_per_kw_commitment, const u8 *local_shutdown_scriptpubkey, const u8 *remote_shutdown_scriptpubkey, u32 lease_start_blockheight, u32 lease_expiry, const secp256k1_ecdsa_signature *lease_commit_sig, u32 lease_chan_max_msat, u16 lease_chan_max_ppt) { u16 local_shutdown_len = tal_count(local_shutdown_scriptpubkey); u16 remote_shutdown_len = tal_count(remote_shutdown_scriptpubkey); @@ -526,6 +528,7 @@ u8 *towire_dualopend_commit_rcvd(const tal_t *ctx, const struct channel_config * towire_u8_array(&p, local_shutdown_scriptpubkey, local_shutdown_len); towire_u16(&p, remote_shutdown_len); towire_u8_array(&p, remote_shutdown_scriptpubkey, remote_shutdown_len); + towire_u32(&p, lease_start_blockheight); towire_u32(&p, lease_expiry); if (!lease_commit_sig) towire_bool(&p, false); @@ -538,7 +541,7 @@ u8 *towire_dualopend_commit_rcvd(const tal_t *ctx, const struct channel_config * return memcheck(p, tal_count(p)); } -bool fromwire_dualopend_commit_rcvd(const tal_t *ctx, const void *p, struct channel_config *their_config, struct bitcoin_tx **remote_first_commit, struct penalty_base **pbase, struct bitcoin_signature *first_commit_sig, struct wally_psbt **psbt, struct pubkey *revocation_basepoint, struct pubkey *payment_basepoint, struct pubkey *htlc_basepoint, struct pubkey *delayed_payment_basepoint, struct pubkey *their_per_commit_point, struct pubkey *remote_fundingkey, struct bitcoin_txid *funding_txid, u16 *funding_txout, struct amount_sat *funding_satoshis, struct amount_sat *our_funding_sats, u8 *channel_flags, u32 *feerate_per_kw_funding, u32 *feerate_per_kw_commitment, u8 **local_shutdown_scriptpubkey, u8 **remote_shutdown_scriptpubkey, u32 *lease_expiry, secp256k1_ecdsa_signature **lease_commit_sig, u32 *lease_chan_max_msat, u16 *lease_chan_max_ppt) +bool fromwire_dualopend_commit_rcvd(const tal_t *ctx, const void *p, struct channel_config *their_config, struct bitcoin_tx **remote_first_commit, struct penalty_base **pbase, struct bitcoin_signature *first_commit_sig, struct wally_psbt **psbt, struct pubkey *revocation_basepoint, struct pubkey *payment_basepoint, struct pubkey *htlc_basepoint, struct pubkey *delayed_payment_basepoint, struct pubkey *their_per_commit_point, struct pubkey *remote_fundingkey, struct bitcoin_txid *funding_txid, u16 *funding_txout, struct amount_sat *funding_satoshis, struct amount_sat *our_funding_sats, u8 *channel_flags, u32 *feerate_per_kw_funding, u32 *feerate_per_kw_commitment, u8 **local_shutdown_scriptpubkey, u8 **remote_shutdown_scriptpubkey, u32 *lease_start_blockheight, u32 *lease_expiry, secp256k1_ecdsa_signature **lease_commit_sig, u32 *lease_chan_max_msat, u16 *lease_chan_max_ppt) { u16 local_shutdown_len; u16 remote_shutdown_len; @@ -579,6 +582,7 @@ bool fromwire_dualopend_commit_rcvd(const tal_t *ctx, const void *p, struct chan // 2nd case remote_shutdown_scriptpubkey *remote_shutdown_scriptpubkey = remote_shutdown_len ? tal_arr(ctx, u8, remote_shutdown_len) : NULL; fromwire_u8_array(&cursor, &plen, *remote_shutdown_scriptpubkey, remote_shutdown_len); + *lease_start_blockheight = fromwire_u32(&cursor, &plen); *lease_expiry = fromwire_u32(&cursor, &plen); if (!fromwire_bool(&cursor, &plen)) *lease_commit_sig = NULL; @@ -1074,4 +1078,4 @@ bool fromwire_dualopend_validate_lease_reply(const tal_t *ctx, const void *p, wi } return cursor != NULL; } -// SHA256STAMP:5e2b2c6ce70bfc6f6e2f068e80a490ce36ebdfb50809c365914dd9ea8f4137a8 +// SHA256STAMP:8d6c88b060336c28b978fc1501bbb372d2d525c6a40585d6341157026b8dfd65 diff --git a/openingd/dualopend_wiregen.h b/openingd/dualopend_wiregen.h index 81aec61aecec..d03753420e24 100644 --- a/openingd/dualopend_wiregen.h +++ b/openingd/dualopend_wiregen.h @@ -98,8 +98,8 @@ bool fromwire_dualopend_init(const tal_t *ctx, const void *p, const struct chain /* WIRE: DUALOPEND_REINIT */ /* master-dualopend: peer has reconnected */ -u8 *towire_dualopend_reinit(const tal_t *ctx, const struct chainparams *chainparams, const struct feature_set *our_feature_set, const u8 *their_init_features, const struct channel_config *our_config, const struct channel_config *their_config, const struct channel_id *channel_id, u32 max_to_self_delay, struct amount_msat min_effective_htlc_capacity_msat, const struct per_peer_state *pps, const struct basepoints *our_basepoints, const struct pubkey *our_funding_pubkey, const struct pubkey *their_funding_pubkey, u32 minimum_depth, const struct bitcoin_txid *funding_txid, u16 funding_txout, u32 orignal_feerate_per_kw_funding, u32 most_recent_feerate_per_kw_funding, struct amount_sat funding_satoshi, struct amount_msat our_funding, const struct basepoints *their_basepoints, const struct pubkey *remote_per_commit, const struct wally_psbt *funding_psbt, enum side opener, bool local_funding_locked, bool remote_funding_locked, bool send_shutdown, bool remote_shutdown_received, const u8 *local_shutdown_scriptpubkey, const u8 *remote_shutdown_scriptpubkey, bool remote_funding_sigs_received, const struct fee_states *fee_states, u8 channel_flags, u32 lease_expiry, const secp256k1_ecdsa_signature *lease_commit_sig, u32 lease_chan_max_msat, u16 lease_chan_max_ppt); -bool fromwire_dualopend_reinit(const tal_t *ctx, const void *p, const struct chainparams **chainparams, struct feature_set **our_feature_set, u8 **their_init_features, struct channel_config *our_config, struct channel_config *their_config, struct channel_id *channel_id, u32 *max_to_self_delay, struct amount_msat *min_effective_htlc_capacity_msat, struct per_peer_state **pps, struct basepoints *our_basepoints, struct pubkey *our_funding_pubkey, struct pubkey *their_funding_pubkey, u32 *minimum_depth, struct bitcoin_txid *funding_txid, u16 *funding_txout, u32 *orignal_feerate_per_kw_funding, u32 *most_recent_feerate_per_kw_funding, struct amount_sat *funding_satoshi, struct amount_msat *our_funding, struct basepoints *their_basepoints, struct pubkey *remote_per_commit, struct wally_psbt **funding_psbt, enum side *opener, bool *local_funding_locked, bool *remote_funding_locked, bool *send_shutdown, bool *remote_shutdown_received, u8 **local_shutdown_scriptpubkey, u8 **remote_shutdown_scriptpubkey, bool *remote_funding_sigs_received, struct fee_states **fee_states, u8 *channel_flags, u32 *lease_expiry, secp256k1_ecdsa_signature **lease_commit_sig, u32 *lease_chan_max_msat, u16 *lease_chan_max_ppt); +u8 *towire_dualopend_reinit(const tal_t *ctx, const struct chainparams *chainparams, const struct feature_set *our_feature_set, const u8 *their_init_features, const struct channel_config *our_config, const struct channel_config *their_config, const struct channel_id *channel_id, u32 max_to_self_delay, struct amount_msat min_effective_htlc_capacity_msat, const struct per_peer_state *pps, const struct basepoints *our_basepoints, const struct pubkey *our_funding_pubkey, const struct pubkey *their_funding_pubkey, u32 minimum_depth, const struct bitcoin_txid *funding_txid, u16 funding_txout, u32 orignal_feerate_per_kw_funding, u32 most_recent_feerate_per_kw_funding, struct amount_sat funding_satoshi, struct amount_msat our_funding, const struct basepoints *their_basepoints, const struct pubkey *remote_per_commit, const struct wally_psbt *funding_psbt, enum side opener, bool local_funding_locked, bool remote_funding_locked, bool send_shutdown, bool remote_shutdown_received, const u8 *local_shutdown_scriptpubkey, const u8 *remote_shutdown_scriptpubkey, bool remote_funding_sigs_received, const struct fee_states *fee_states, u8 channel_flags, u32 lease_start_blockheight, u32 lease_expiry, const secp256k1_ecdsa_signature *lease_commit_sig, u32 lease_chan_max_msat, u16 lease_chan_max_ppt); +bool fromwire_dualopend_reinit(const tal_t *ctx, const void *p, const struct chainparams **chainparams, struct feature_set **our_feature_set, u8 **their_init_features, struct channel_config *our_config, struct channel_config *their_config, struct channel_id *channel_id, u32 *max_to_self_delay, struct amount_msat *min_effective_htlc_capacity_msat, struct per_peer_state **pps, struct basepoints *our_basepoints, struct pubkey *our_funding_pubkey, struct pubkey *their_funding_pubkey, u32 *minimum_depth, struct bitcoin_txid *funding_txid, u16 *funding_txout, u32 *orignal_feerate_per_kw_funding, u32 *most_recent_feerate_per_kw_funding, struct amount_sat *funding_satoshi, struct amount_msat *our_funding, struct basepoints *their_basepoints, struct pubkey *remote_per_commit, struct wally_psbt **funding_psbt, enum side *opener, bool *local_funding_locked, bool *remote_funding_locked, bool *send_shutdown, bool *remote_shutdown_received, u8 **local_shutdown_scriptpubkey, u8 **remote_shutdown_scriptpubkey, bool *remote_funding_sigs_received, struct fee_states **fee_states, u8 *channel_flags, u32 *lease_start_blockheight, u32 *lease_expiry, secp256k1_ecdsa_signature **lease_commit_sig, u32 *lease_chan_max_msat, u16 *lease_chan_max_ppt); /* WIRE: DUALOPEND_GOT_OFFER */ /* dualopend->master: they offered channel */ @@ -139,8 +139,8 @@ bool fromwire_dualopend_rbf_init(const tal_t *ctx, const void *p, struct amount_ /* WIRE: DUALOPEND_COMMIT_RCVD */ /* dualopend->master: ready to commit channel open to database and */ /* get some signatures for the funding_tx. */ -u8 *towire_dualopend_commit_rcvd(const tal_t *ctx, const struct channel_config *their_config, const struct bitcoin_tx *remote_first_commit, const struct penalty_base *pbase, const struct bitcoin_signature *first_commit_sig, const struct wally_psbt *psbt, const struct pubkey *revocation_basepoint, const struct pubkey *payment_basepoint, const struct pubkey *htlc_basepoint, const struct pubkey *delayed_payment_basepoint, const struct pubkey *their_per_commit_point, const struct pubkey *remote_fundingkey, const struct bitcoin_txid *funding_txid, u16 funding_txout, struct amount_sat funding_satoshis, struct amount_sat our_funding_sats, u8 channel_flags, u32 feerate_per_kw_funding, u32 feerate_per_kw_commitment, const u8 *local_shutdown_scriptpubkey, const u8 *remote_shutdown_scriptpubkey, u32 lease_expiry, const secp256k1_ecdsa_signature *lease_commit_sig, u32 lease_chan_max_msat, u16 lease_chan_max_ppt); -bool fromwire_dualopend_commit_rcvd(const tal_t *ctx, const void *p, struct channel_config *their_config, struct bitcoin_tx **remote_first_commit, struct penalty_base **pbase, struct bitcoin_signature *first_commit_sig, struct wally_psbt **psbt, struct pubkey *revocation_basepoint, struct pubkey *payment_basepoint, struct pubkey *htlc_basepoint, struct pubkey *delayed_payment_basepoint, struct pubkey *their_per_commit_point, struct pubkey *remote_fundingkey, struct bitcoin_txid *funding_txid, u16 *funding_txout, struct amount_sat *funding_satoshis, struct amount_sat *our_funding_sats, u8 *channel_flags, u32 *feerate_per_kw_funding, u32 *feerate_per_kw_commitment, u8 **local_shutdown_scriptpubkey, u8 **remote_shutdown_scriptpubkey, u32 *lease_expiry, secp256k1_ecdsa_signature **lease_commit_sig, u32 *lease_chan_max_msat, u16 *lease_chan_max_ppt); +u8 *towire_dualopend_commit_rcvd(const tal_t *ctx, const struct channel_config *their_config, const struct bitcoin_tx *remote_first_commit, const struct penalty_base *pbase, const struct bitcoin_signature *first_commit_sig, const struct wally_psbt *psbt, const struct pubkey *revocation_basepoint, const struct pubkey *payment_basepoint, const struct pubkey *htlc_basepoint, const struct pubkey *delayed_payment_basepoint, const struct pubkey *their_per_commit_point, const struct pubkey *remote_fundingkey, const struct bitcoin_txid *funding_txid, u16 funding_txout, struct amount_sat funding_satoshis, struct amount_sat our_funding_sats, u8 channel_flags, u32 feerate_per_kw_funding, u32 feerate_per_kw_commitment, const u8 *local_shutdown_scriptpubkey, const u8 *remote_shutdown_scriptpubkey, u32 lease_start_blockheight, u32 lease_expiry, const secp256k1_ecdsa_signature *lease_commit_sig, u32 lease_chan_max_msat, u16 lease_chan_max_ppt); +bool fromwire_dualopend_commit_rcvd(const tal_t *ctx, const void *p, struct channel_config *their_config, struct bitcoin_tx **remote_first_commit, struct penalty_base **pbase, struct bitcoin_signature *first_commit_sig, struct wally_psbt **psbt, struct pubkey *revocation_basepoint, struct pubkey *payment_basepoint, struct pubkey *htlc_basepoint, struct pubkey *delayed_payment_basepoint, struct pubkey *their_per_commit_point, struct pubkey *remote_fundingkey, struct bitcoin_txid *funding_txid, u16 *funding_txout, struct amount_sat *funding_satoshis, struct amount_sat *our_funding_sats, u8 *channel_flags, u32 *feerate_per_kw_funding, u32 *feerate_per_kw_commitment, u8 **local_shutdown_scriptpubkey, u8 **remote_shutdown_scriptpubkey, u32 *lease_start_blockheight, u32 *lease_expiry, secp256k1_ecdsa_signature **lease_commit_sig, u32 *lease_chan_max_msat, u16 *lease_chan_max_ppt); /* WIRE: DUALOPEND_PSBT_CHANGED */ /* dualopend->master: peer updated the psbt */ @@ -237,4 +237,4 @@ bool fromwire_dualopend_validate_lease_reply(const tal_t *ctx, const void *p, wi #endif /* LIGHTNING_OPENINGD_DUALOPEND_WIREGEN_H */ -// SHA256STAMP:5e2b2c6ce70bfc6f6e2f068e80a490ce36ebdfb50809c365914dd9ea8f4137a8 +// SHA256STAMP:8d6c88b060336c28b978fc1501bbb372d2d525c6a40585d6341157026b8dfd65 diff --git a/openingd/openingd.c b/openingd/openingd.c index a96024ffdc36..70bde6b0d057 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -510,7 +510,7 @@ static bool funder_finalize_channel_setup(struct state *state, &state->funding_txid, state->funding_txout, state->minimum_depth, - 0, /* No lease lock */ + NULL, 0, /* No channel lease */ state->funding, local_msat, take(new_fee_states(NULL, LOCAL, @@ -1001,7 +1001,7 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) &state->funding_txid, state->funding_txout, state->minimum_depth, - 0, /* No channel lease */ + NULL, 0, /* No channel lease */ state->funding, state->push_msat, take(new_fee_states(NULL, REMOTE, diff --git a/openingd/openingd_wiregen.c b/openingd/openingd_wiregen.c index 7f615aa0996d..8b0623357fdd 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:d2fcabdf157b098608e47dcdc37db0f46fe8d466d74159969544d7c4bb77f061 +// SHA256STAMP:293e24db57d783e163f97f3b696f3ea0a74f1bb31e4b06fd37e5cc915b177f52 diff --git a/openingd/openingd_wiregen.h b/openingd/openingd_wiregen.h index 047c82110783..5e48fd3884ad 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:d2fcabdf157b098608e47dcdc37db0f46fe8d466d74159969544d7c4bb77f061 +// SHA256STAMP:293e24db57d783e163f97f3b696f3ea0a74f1bb31e4b06fd37e5cc915b177f52 diff --git a/tests/fuzz/fuzz-initial_channel.c b/tests/fuzz/fuzz-initial_channel.c index c2e690e58b59..06e1e89bdc20 100644 --- a/tests/fuzz/fuzz-initial_channel.c +++ b/tests/fuzz/fuzz-initial_channel.c @@ -34,7 +34,7 @@ void run(const uint8_t *data, size_t size) u32 funding_txout, minimum_depth; struct amount_sat funding, max; struct amount_msat local_msatoshi; - u32 feerate_per_kw; + u32 feerate_per_kw, blockheight, lease_expiry; struct channel_config local, remote; struct basepoints local_basepoints, remote_basepoints; struct pubkey local_funding_pubkey, remote_funding_pubkey; @@ -51,6 +51,8 @@ void run(const uint8_t *data, size_t size) if (amount_sat_greater(funding, max)) funding = max; feerate_per_kw = fromwire_u32(&data, &size); + blockheight = fromwire_u32(&data, &size); + lease_expiry = fromwire_u32(&data, &size); fromwire_channel_config(&data, &size, &local); fromwire_channel_config(&data, &size, &remote); fromwire_basepoints(&data, &size, &local_basepoints); @@ -66,12 +68,20 @@ void run(const uint8_t *data, size_t size) return; for (enum side opener = 0; opener < NUM_SIDES; opener++) { - channel = new_initial_channel(tmpctx, &cid, &funding_txid, funding_txout, - minimum_depth, funding, local_msatoshi, - take(new_fee_states(NULL, opener, &feerate_per_kw)), - &local, &remote, &local_basepoints, - &remote_basepoints, &local_funding_pubkey, - &remote_funding_pubkey, option_static_remotekey, + channel = new_initial_channel(tmpctx, &cid, &funding_txid, + funding_txout, minimum_depth, + take(new_height_states(NULL, opener, + &blockheight)), + lease_expiry, + funding, local_msatoshi, + take(new_fee_states(NULL, opener, + &feerate_per_kw)), + &local, &remote, + &local_basepoints, + &remote_basepoints, + &local_funding_pubkey, + &remote_funding_pubkey, + option_static_remotekey, option_anchor_outputs, opener); /* TODO: make initial_channel_tx() work with ASAN.. */ diff --git a/tools/generate-wire.py b/tools/generate-wire.py index 38c372d9cc4e..9845c9a0bfce 100755 --- a/tools/generate-wire.py +++ b/tools/generate-wire.py @@ -231,6 +231,7 @@ class Type(FieldSet): 'bitcoin_tx_output', 'exclude_entry', 'fee_states', + 'height_states', 'onionreply', 'feature_set', 'onionmsg_path', diff --git a/wallet/db.c b/wallet/db.c index 1eb917a9beec..472f12923e68 100644 --- a/wallet/db.c +++ b/wallet/db.c @@ -62,6 +62,10 @@ static void fillin_missing_local_basepoints(struct lightningd *ld, struct db *db, const struct migration_context *mc); +static void fillin_missing_channel_blockheights(struct lightningd *ld, + struct db *db, + const struct migration_context *mc); + /* Do not reorder or remove elements from this array, it is used to * migrate existing databases from a previous state, based on the * string indices */ @@ -732,10 +736,18 @@ static struct migration dbmigrations[] = { {SQL("ALTER TABLE channel_funding_inflights ADD lease_chan_max_msat BIGINT DEFAULT NULL"), NULL}, {SQL("ALTER TABLE channel_funding_inflights ADD lease_chan_max_ppt INTEGER DEFAULT NULL"), NULL}, {SQL("ALTER TABLE channel_funding_inflights ADD lease_expiry INTEGER DEFAULT 0"), NULL}, + {SQL("ALTER TABLE channel_funding_inflights ADD lease_blockheight_start INTEGER DEFAULT 0"), NULL}, {SQL("ALTER TABLE channels ADD lease_commit_sig BLOB DEFAULT NULL"), NULL}, {SQL("ALTER TABLE channels ADD lease_chan_max_msat INTEGER DEFAULT NULL"), NULL}, {SQL("ALTER TABLE channels ADD lease_chan_max_ppt INTEGER DEFAULT NULL"), NULL}, {SQL("ALTER TABLE channels ADD lease_expiry INTEGER DEFAULT 0"), NULL}, + {SQL("CREATE TABLE channel_blockheights (" + " channel_id BIGINT REFERENCES channels(id) ON DELETE CASCADE," + " hstate INTEGER," + " blockheight INTEGER," + " UNIQUE (channel_id, hstate)" + ");"), + fillin_missing_channel_blockheights}, }; /* Leak tracking. */ @@ -1428,6 +1440,33 @@ static void fillin_missing_local_basepoints(struct lightningd *ld, tal_free(stmt); } +/* New 'channel_blockheights' table, every existing channel gets a + * 'initial blockheight' of 0 */ +static void fillin_missing_channel_blockheights(struct lightningd *ld, + struct db *db, + const struct migration_context *mc) +{ + struct db_stmt *stmt; + + /* Set all existing channels to 0 */ + /* If we're funder (LOCAL=0): + * Then our blockheight is set last (SENT_ADD_ACK_REVOCATION = 4) */ + stmt = db_prepare_v2(db, + SQL("INSERT INTO channel_blockheights" + " (channel_id, hstate, blockheight)" + " SELECT id, 4, 0 FROM channels" + " WHERE funder = 0;")); + db_exec_prepared_v2(take(stmt)); + /* If they're funder (REMOTE=1): + * Then their blockheight is last (RCVD_ADD_ACK_REVOCATION = 14) */ + stmt = db_prepare_v2(db, + SQL("INSERT INTO channel_blockheights" + " (channel_id, hstate, blockheight)" + " SELECT id, 14, 0 FROM channels" + " WHERE funder = 1;")); + db_exec_prepared_v2(take(stmt)); +} + void migrate_inflight_last_tx_to_psbt(struct lightningd *ld, struct db *db, const struct migration_context *mc) diff --git a/wallet/db_postgres_sqlgen.c b/wallet/db_postgres_sqlgen.c index fc1005c292d4..5f79ff32d488 100644 --- a/wallet/db_postgres_sqlgen.c +++ b/wallet/db_postgres_sqlgen.c @@ -980,6 +980,12 @@ struct db_query db_postgres_queries[] = { .placeholders = 0, .readonly = false, }, + { + .name = "ALTER TABLE channel_funding_inflights ADD lease_blockheight_start INTEGER DEFAULT 0", + .query = "ALTER TABLE channel_funding_inflights ADD lease_blockheight_start INTEGER DEFAULT 0", + .placeholders = 0, + .readonly = false, + }, { .name = "ALTER TABLE channels ADD lease_commit_sig BLOB DEFAULT NULL", .query = "ALTER TABLE channels ADD lease_commit_sig BYTEA DEFAULT NULL", @@ -1004,6 +1010,12 @@ struct db_query db_postgres_queries[] = { .placeholders = 0, .readonly = false, }, + { + .name = "CREATE TABLE channel_blockheights ( channel_id BIGINT REFERENCES channels(id) ON DELETE CASCADE, hstate INTEGER, blockheight INTEGER, UNIQUE (channel_id, hstate));", + .query = "CREATE TABLE channel_blockheights ( channel_id BIGINT REFERENCES channels(id) ON DELETE CASCADE, hstate INTEGER, blockheight INTEGER, UNIQUE (channel_id, hstate));", + .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", @@ -1100,6 +1112,18 @@ struct db_query db_postgres_queries[] = { .placeholders = 6, .readonly = false, }, + { + .name = "INSERT INTO channel_blockheights (channel_id, hstate, blockheight) SELECT id, 4, 0 FROM channels WHERE funder = 0;", + .query = "INSERT INTO channel_blockheights (channel_id, hstate, blockheight) SELECT id, 4, 0 FROM channels WHERE funder = 0;", + .placeholders = 0, + .readonly = false, + }, + { + .name = "INSERT INTO channel_blockheights (channel_id, hstate, blockheight) SELECT id, 14, 0 FROM channels WHERE funder = 1;", + .query = "INSERT INTO channel_blockheights (channel_id, hstate, blockheight) SELECT id, 14, 0 FROM channels WHERE funder = 1;", + .placeholders = 0, + .readonly = false, + }, { .name = "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;", .query = "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;", @@ -1341,9 +1365,15 @@ struct db_query db_postgres_queries[] = { .readonly = true, }, { - .name = "INSERT INTO channel_funding_inflights ( channel_id, funding_tx_id, funding_tx_outnum, funding_feerate, funding_satoshi, our_funding_satoshi, funding_psbt, last_tx, last_sig) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);", - .query = "INSERT INTO channel_funding_inflights ( channel_id, funding_tx_id, funding_tx_outnum, funding_feerate, funding_satoshi, our_funding_satoshi, funding_psbt, last_tx, last_sig) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9);", - .placeholders = 9, + .name = "SELECT hstate, blockheight FROM channel_blockheights WHERE channel_id = ?", + .query = "SELECT hstate, blockheight FROM channel_blockheights WHERE channel_id = $1", + .placeholders = 1, + .readonly = true, + }, + { + .name = "INSERT INTO channel_funding_inflights ( channel_id, funding_tx_id, funding_tx_outnum, funding_feerate, funding_satoshi, our_funding_satoshi, funding_psbt, last_tx, last_sig, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt, lease_expiry, lease_blockheight_start) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", + .query = "INSERT INTO channel_funding_inflights ( channel_id, funding_tx_id, funding_tx_outnum, funding_feerate, funding_satoshi, our_funding_satoshi, funding_psbt, last_tx, last_sig, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt, lease_expiry, lease_blockheight_start) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14);", + .placeholders = 14, .readonly = false, }, { @@ -1359,8 +1389,8 @@ struct db_query db_postgres_queries[] = { .readonly = false, }, { - .name = "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, lease_expiry, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt FROM channel_funding_inflights WHERE channel_id = ? ORDER BY funding_feerate", - .query = "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, lease_expiry, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt FROM channel_funding_inflights WHERE channel_id = $1 ORDER BY funding_feerate", + .name = "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, lease_expiry, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt, lease_blockheight_start FROM channel_funding_inflights WHERE channel_id = ? ORDER BY funding_feerate", + .query = "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, lease_expiry, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt, lease_blockheight_start FROM channel_funding_inflights WHERE channel_id = $1 ORDER BY funding_feerate", .placeholders = 1, .readonly = true, }, @@ -1460,6 +1490,18 @@ struct db_query db_postgres_queries[] = { .placeholders = 3, .readonly = false, }, + { + .name = "DELETE FROM channel_blockheights WHERE channel_id=?", + .query = "DELETE FROM channel_blockheights WHERE channel_id=$1", + .placeholders = 1, + .readonly = false, + }, + { + .name = "INSERT INTO channel_blockheights VALUES(?, ?, ?)", + .query = "INSERT INTO channel_blockheights VALUES($1, $2, $3)", + .placeholders = 3, + .readonly = false, + }, { .name = "UPDATE channels SET last_sent_commit=? WHERE id=?", .query = "UPDATE channels SET last_sent_commit=$1 WHERE id=$2", @@ -1966,10 +2008,10 @@ struct db_query db_postgres_queries[] = { }, }; -#define DB_POSTGRES_QUERY_COUNT 326 +#define DB_POSTGRES_QUERY_COUNT 333 #endif /* HAVE_POSTGRES */ #endif /* LIGHTNINGD_WALLET_GEN_DB_POSTGRES */ -// SHA256STAMP:06e51ede39e83d9416af098b0d38f8c778109558d3b9483cfc946554940dfab2 +// SHA256STAMP:4aa3c138e6c172aff0958062fbf1cdfd14194424349c533a46a0407b7131b7be diff --git a/wallet/db_sqlite3_sqlgen.c b/wallet/db_sqlite3_sqlgen.c index 83f12d32f56c..b0bca4a2b0e2 100644 --- a/wallet/db_sqlite3_sqlgen.c +++ b/wallet/db_sqlite3_sqlgen.c @@ -980,6 +980,12 @@ struct db_query db_sqlite3_queries[] = { .placeholders = 0, .readonly = false, }, + { + .name = "ALTER TABLE channel_funding_inflights ADD lease_blockheight_start INTEGER DEFAULT 0", + .query = "ALTER TABLE channel_funding_inflights ADD lease_blockheight_start INTEGER DEFAULT 0", + .placeholders = 0, + .readonly = false, + }, { .name = "ALTER TABLE channels ADD lease_commit_sig BLOB DEFAULT NULL", .query = "ALTER TABLE channels ADD lease_commit_sig BLOB DEFAULT NULL", @@ -1004,6 +1010,12 @@ struct db_query db_sqlite3_queries[] = { .placeholders = 0, .readonly = false, }, + { + .name = "CREATE TABLE channel_blockheights ( channel_id BIGINT REFERENCES channels(id) ON DELETE CASCADE, hstate INTEGER, blockheight INTEGER, UNIQUE (channel_id, hstate));", + .query = "CREATE TABLE channel_blockheights ( channel_id INTEGER REFERENCES channels(id) ON DELETE CASCADE, hstate INTEGER, blockheight INTEGER, UNIQUE (channel_id, hstate));", + .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 = ?", @@ -1100,6 +1112,18 @@ struct db_query db_sqlite3_queries[] = { .placeholders = 6, .readonly = false, }, + { + .name = "INSERT INTO channel_blockheights (channel_id, hstate, blockheight) SELECT id, 4, 0 FROM channels WHERE funder = 0;", + .query = "INSERT INTO channel_blockheights (channel_id, hstate, blockheight) SELECT id, 4, 0 FROM channels WHERE funder = 0;", + .placeholders = 0, + .readonly = false, + }, + { + .name = "INSERT INTO channel_blockheights (channel_id, hstate, blockheight) SELECT id, 14, 0 FROM channels WHERE funder = 1;", + .query = "INSERT INTO channel_blockheights (channel_id, hstate, blockheight) SELECT id, 14, 0 FROM channels WHERE funder = 1;", + .placeholders = 0, + .readonly = false, + }, { .name = "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;", .query = "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;", @@ -1341,9 +1365,15 @@ struct db_query db_sqlite3_queries[] = { .readonly = true, }, { - .name = "INSERT INTO channel_funding_inflights ( channel_id, funding_tx_id, funding_tx_outnum, funding_feerate, funding_satoshi, our_funding_satoshi, funding_psbt, last_tx, last_sig) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);", - .query = "INSERT INTO channel_funding_inflights ( channel_id, funding_tx_id, funding_tx_outnum, funding_feerate, funding_satoshi, our_funding_satoshi, funding_psbt, last_tx, last_sig) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);", - .placeholders = 9, + .name = "SELECT hstate, blockheight FROM channel_blockheights WHERE channel_id = ?", + .query = "SELECT hstate, blockheight FROM channel_blockheights WHERE channel_id = ?", + .placeholders = 1, + .readonly = true, + }, + { + .name = "INSERT INTO channel_funding_inflights ( channel_id, funding_tx_id, funding_tx_outnum, funding_feerate, funding_satoshi, our_funding_satoshi, funding_psbt, last_tx, last_sig, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt, lease_expiry, lease_blockheight_start) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", + .query = "INSERT INTO channel_funding_inflights ( channel_id, funding_tx_id, funding_tx_outnum, funding_feerate, funding_satoshi, our_funding_satoshi, funding_psbt, last_tx, last_sig, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt, lease_expiry, lease_blockheight_start) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", + .placeholders = 14, .readonly = false, }, { @@ -1359,8 +1389,8 @@ struct db_query db_sqlite3_queries[] = { .readonly = false, }, { - .name = "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, lease_expiry, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt FROM channel_funding_inflights WHERE channel_id = ? ORDER BY funding_feerate", - .query = "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, lease_expiry, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt FROM channel_funding_inflights WHERE channel_id = ? ORDER BY funding_feerate", + .name = "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, lease_expiry, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt, lease_blockheight_start FROM channel_funding_inflights WHERE channel_id = ? ORDER BY funding_feerate", + .query = "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, lease_expiry, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt, lease_blockheight_start FROM channel_funding_inflights WHERE channel_id = ? ORDER BY funding_feerate", .placeholders = 1, .readonly = true, }, @@ -1460,6 +1490,18 @@ struct db_query db_sqlite3_queries[] = { .placeholders = 3, .readonly = false, }, + { + .name = "DELETE FROM channel_blockheights WHERE channel_id=?", + .query = "DELETE FROM channel_blockheights WHERE channel_id=?", + .placeholders = 1, + .readonly = false, + }, + { + .name = "INSERT INTO channel_blockheights VALUES(?, ?, ?)", + .query = "INSERT INTO channel_blockheights VALUES(?, ?, ?)", + .placeholders = 3, + .readonly = false, + }, { .name = "UPDATE channels SET last_sent_commit=? WHERE id=?", .query = "UPDATE channels SET last_sent_commit=? WHERE id=?", @@ -1966,10 +2008,10 @@ struct db_query db_sqlite3_queries[] = { }, }; -#define DB_SQLITE3_QUERY_COUNT 326 +#define DB_SQLITE3_QUERY_COUNT 333 #endif /* HAVE_SQLITE3 */ #endif /* LIGHTNINGD_WALLET_GEN_DB_SQLITE3 */ -// SHA256STAMP:06e51ede39e83d9416af098b0d38f8c778109558d3b9483cfc946554940dfab2 +// SHA256STAMP:4aa3c138e6c172aff0958062fbf1cdfd14194424349c533a46a0407b7131b7be diff --git a/wallet/statements_gettextgen.po b/wallet/statements_gettextgen.po index 74814b4738be..9b064071f8e4 100644 --- a/wallet/statements_gettextgen.po +++ b/wallet/statements_gettextgen.po @@ -1,744 +1,760 @@ -#: wallet/db.c:69 +#: wallet/db.c:73 msgid "CREATE TABLE version (version INTEGER)" msgstr "" -#: wallet/db.c:70 +#: wallet/db.c:74 msgid "INSERT INTO version VALUES (1)" msgstr "" -#: wallet/db.c:71 +#: wallet/db.c:75 msgid "CREATE TABLE outputs ( prev_out_tx BLOB, prev_out_index INTEGER, value BIGINT, type INTEGER, status INTEGER, keyindex INTEGER, PRIMARY KEY (prev_out_tx, prev_out_index));" msgstr "" -#: wallet/db.c:80 +#: wallet/db.c:84 msgid "CREATE TABLE vars ( name VARCHAR(32), val VARCHAR(255), PRIMARY KEY (name));" msgstr "" -#: wallet/db.c:86 +#: wallet/db.c:90 msgid "CREATE TABLE shachains ( id BIGSERIAL, min_index BIGINT, num_valid BIGINT, PRIMARY KEY (id));" msgstr "" -#: wallet/db.c:93 +#: wallet/db.c:97 msgid "CREATE TABLE shachain_known ( shachain_id BIGINT REFERENCES shachains(id) ON DELETE CASCADE, pos INTEGER, idx BIGINT, hash BLOB, PRIMARY KEY (shachain_id, pos));" msgstr "" -#: wallet/db.c:101 +#: wallet/db.c:105 msgid "CREATE TABLE peers ( id BIGSERIAL, node_id BLOB UNIQUE, address TEXT, PRIMARY KEY (id));" msgstr "" -#: wallet/db.c:108 +#: wallet/db.c:112 msgid "CREATE TABLE channels ( id BIGSERIAL, peer_id BIGINT REFERENCES peers(id) ON DELETE CASCADE, short_channel_id TEXT, channel_config_local BIGINT, channel_config_remote BIGINT, state INTEGER, funder INTEGER, channel_flags INTEGER, minimum_depth INTEGER, next_index_local BIGINT, next_index_remote BIGINT, next_htlc_id BIGINT, funding_tx_id BLOB, funding_tx_outnum INTEGER, funding_satoshi BIGINT, funding_locked_remote INTEGER, push_msatoshi BIGINT, msatoshi_local BIGINT, fundingkey_remote BLOB, revocation_basepoint_remote BLOB, payment_basepoint_remote BLOB, htlc_basepoint_remote BLOB, delayed_payment_basepoint_remote BLOB, per_commit_remote BLOB, old_per_commit_remote BLOB, local_feerate_per_kw INTEGER, remote_feerate_per_kw INTEGER, shachain_remote_id BIGINT, shutdown_scriptpubkey_remote BLOB, shutdown_keyidx_local BIGINT, last_sent_commit_state BIGINT, last_sent_commit_id INTEGER, last_tx BLOB, last_sig BLOB, closing_fee_received INTEGER, closing_sig_received BLOB, PRIMARY KEY (id));" msgstr "" -#: wallet/db.c:150 +#: wallet/db.c:154 msgid "CREATE TABLE channel_configs ( id BIGSERIAL, dust_limit_satoshis BIGINT, max_htlc_value_in_flight_msat BIGINT, channel_reserve_satoshis BIGINT, htlc_minimum_msat BIGINT, to_self_delay INTEGER, max_accepted_htlcs INTEGER, PRIMARY KEY (id));" msgstr "" -#: wallet/db.c:161 +#: wallet/db.c:165 msgid "CREATE TABLE channel_htlcs ( id BIGSERIAL, channel_id BIGINT REFERENCES channels(id) ON DELETE CASCADE, channel_htlc_id BIGINT, direction INTEGER, origin_htlc BIGINT, msatoshi BIGINT, cltv_expiry INTEGER, payment_hash BLOB, payment_key BLOB, routing_onion BLOB, failuremsg BLOB, malformed_onion INTEGER, hstate INTEGER, shared_secret BLOB, PRIMARY KEY (id), UNIQUE (channel_id, channel_htlc_id, direction));" msgstr "" -#: wallet/db.c:181 +#: wallet/db.c:185 msgid "CREATE TABLE invoices ( id BIGSERIAL, state INTEGER, msatoshi BIGINT, payment_hash BLOB, payment_key BLOB, label TEXT, PRIMARY KEY (id), UNIQUE (label), UNIQUE (payment_hash));" msgstr "" -#: wallet/db.c:193 +#: wallet/db.c:197 msgid "CREATE TABLE payments ( id BIGSERIAL, timestamp INTEGER, status INTEGER, payment_hash BLOB, direction INTEGER, destination BLOB, msatoshi BIGINT, PRIMARY KEY (id), UNIQUE (payment_hash));" msgstr "" -#: wallet/db.c:206 +#: wallet/db.c:210 msgid "ALTER TABLE invoices ADD expiry_time BIGINT;" msgstr "" -#: wallet/db.c:207 +#: wallet/db.c:211 msgid "UPDATE invoices SET expiry_time=9223372036854775807;" msgstr "" -#: wallet/db.c:209 +#: wallet/db.c:213 msgid "ALTER TABLE invoices ADD pay_index BIGINT;" msgstr "" -#: wallet/db.c:210 +#: wallet/db.c:214 msgid "CREATE UNIQUE INDEX invoices_pay_index ON invoices(pay_index);" msgstr "" -#: wallet/db.c:212 +#: wallet/db.c:216 msgid "UPDATE invoices SET pay_index=id WHERE state=1;" msgstr "" -#: wallet/db.c:215 +#: wallet/db.c:219 msgid "INSERT INTO vars(name, val) VALUES('next_pay_index', COALESCE((SELECT MAX(pay_index) FROM invoices WHERE state=1), 0) + 1 );" msgstr "" -#: wallet/db.c:224 +#: wallet/db.c:228 msgid "ALTER TABLE channels ADD first_blocknum BIGINT;" msgstr "" -#: wallet/db.c:225 +#: wallet/db.c:229 msgid "UPDATE channels SET first_blocknum=1 WHERE short_channel_id IS NOT NULL;" msgstr "" -#: wallet/db.c:227 +#: wallet/db.c:231 msgid "ALTER TABLE outputs ADD COLUMN channel_id BIGINT;" msgstr "" -#: wallet/db.c:228 +#: wallet/db.c:232 msgid "ALTER TABLE outputs ADD COLUMN peer_id BLOB;" msgstr "" -#: wallet/db.c:229 +#: wallet/db.c:233 msgid "ALTER TABLE outputs ADD COLUMN commitment_point BLOB;" msgstr "" -#: wallet/db.c:230 +#: wallet/db.c:234 msgid "ALTER TABLE invoices ADD COLUMN msatoshi_received BIGINT;" msgstr "" -#: wallet/db.c:232 +#: wallet/db.c:236 msgid "UPDATE invoices SET msatoshi_received=0 WHERE state=1;" msgstr "" -#: wallet/db.c:233 +#: wallet/db.c:237 msgid "ALTER TABLE channels ADD COLUMN last_was_revoke INTEGER;" msgstr "" -#: wallet/db.c:237 wallet/db.c:530 +#: wallet/db.c:241 wallet/db.c:534 msgid "ALTER TABLE payments RENAME TO temp_payments;" msgstr "" -#: wallet/db.c:238 +#: wallet/db.c:242 msgid "CREATE TABLE payments ( id BIGSERIAL, timestamp INTEGER, status INTEGER, payment_hash BLOB, destination BLOB, msatoshi BIGINT, PRIMARY KEY (id), UNIQUE (payment_hash));" msgstr "" -#: wallet/db.c:249 +#: wallet/db.c:253 msgid "INSERT INTO payments SELECT id, timestamp, status, payment_hash, destination, msatoshi FROM temp_payments WHERE direction=1;" msgstr "" -#: wallet/db.c:252 wallet/db.c:605 +#: wallet/db.c:256 wallet/db.c:609 msgid "DROP TABLE temp_payments;" msgstr "" -#: wallet/db.c:254 +#: wallet/db.c:258 msgid "ALTER TABLE payments ADD COLUMN payment_preimage BLOB;" msgstr "" -#: wallet/db.c:256 +#: wallet/db.c:260 msgid "ALTER TABLE payments ADD COLUMN path_secrets BLOB;" msgstr "" -#: wallet/db.c:259 +#: wallet/db.c:263 msgid "ALTER TABLE invoices ADD paid_timestamp BIGINT;" msgstr "" -#: wallet/db.c:260 +#: wallet/db.c:264 msgid "UPDATE invoices SET paid_timestamp = CURRENT_TIMESTAMP() WHERE state = 1;" msgstr "" -#: wallet/db.c:268 +#: wallet/db.c:272 msgid "ALTER TABLE payments ADD COLUMN route_nodes BLOB;" msgstr "" -#: wallet/db.c:269 +#: wallet/db.c:273 msgid "ALTER TABLE payments ADD COLUMN route_channels BLOB;" msgstr "" -#: wallet/db.c:270 +#: wallet/db.c:274 msgid "CREATE TABLE htlc_sigs (channelid INTEGER REFERENCES channels(id) ON DELETE CASCADE, signature BLOB);" msgstr "" -#: wallet/db.c:273 +#: wallet/db.c:277 msgid "CREATE INDEX channel_idx ON htlc_sigs (channelid)" msgstr "" -#: wallet/db.c:275 +#: wallet/db.c:279 msgid "DELETE FROM channels WHERE state=1" msgstr "" -#: wallet/db.c:277 +#: wallet/db.c:281 msgid "CREATE TABLE db_upgrades (upgrade_from INTEGER, lightning_version TEXT);" msgstr "" -#: wallet/db.c:281 wallet/db.c:471 +#: wallet/db.c:285 wallet/db.c:475 msgid "DELETE FROM peers WHERE id NOT IN (SELECT peer_id FROM channels);" msgstr "" -#: wallet/db.c:285 +#: wallet/db.c:289 msgid "UPDATE channels SET STATE = 8 WHERE state > 8;" msgstr "" -#: wallet/db.c:287 +#: wallet/db.c:291 msgid "ALTER TABLE invoices ADD bolt11 TEXT;" msgstr "" -#: wallet/db.c:291 +#: wallet/db.c:295 msgid "CREATE TABLE blocks (height INT, hash BLOB, prev_hash BLOB, UNIQUE(height));" msgstr "" -#: wallet/db.c:301 +#: wallet/db.c:305 msgid "ALTER TABLE outputs ADD COLUMN confirmation_height INTEGER REFERENCES blocks(height) ON DELETE SET NULL;" msgstr "" -#: wallet/db.c:304 +#: wallet/db.c:308 msgid "ALTER TABLE outputs ADD COLUMN spend_height INTEGER REFERENCES blocks(height) ON DELETE SET NULL;" msgstr "" -#: wallet/db.c:308 +#: wallet/db.c:312 msgid "CREATE INDEX output_height_idx ON outputs (confirmation_height, spend_height);" msgstr "" -#: wallet/db.c:311 +#: wallet/db.c:315 msgid "CREATE TABLE utxoset ( txid BLOB, outnum INT, blockheight INT REFERENCES blocks(height) ON DELETE CASCADE, spendheight INT REFERENCES blocks(height) ON DELETE SET NULL, txindex INT, scriptpubkey BLOB, satoshis BIGINT, PRIMARY KEY(txid, outnum));" msgstr "" -#: wallet/db.c:321 +#: wallet/db.c:325 msgid "CREATE INDEX short_channel_id ON utxoset (blockheight, txindex, outnum)" msgstr "" -#: wallet/db.c:326 +#: wallet/db.c:330 msgid "CREATE INDEX utxoset_spend ON utxoset (spendheight)" msgstr "" -#: wallet/db.c:328 +#: wallet/db.c:332 msgid "UPDATE channels SET shutdown_keyidx_local=0 WHERE shutdown_keyidx_local = -1;" msgstr "" -#: wallet/db.c:334 +#: wallet/db.c:338 msgid "ALTER TABLE payments ADD failonionreply BLOB;" msgstr "" -#: wallet/db.c:336 +#: wallet/db.c:340 msgid "ALTER TABLE payments ADD faildestperm INTEGER;" msgstr "" -#: wallet/db.c:338 +#: wallet/db.c:342 msgid "ALTER TABLE payments ADD failindex INTEGER;" msgstr "" -#: wallet/db.c:340 +#: wallet/db.c:344 msgid "ALTER TABLE payments ADD failcode INTEGER;" msgstr "" -#: wallet/db.c:341 +#: wallet/db.c:345 msgid "ALTER TABLE payments ADD failnode BLOB;" msgstr "" -#: wallet/db.c:342 +#: wallet/db.c:346 msgid "ALTER TABLE payments ADD failchannel TEXT;" msgstr "" -#: wallet/db.c:344 +#: wallet/db.c:348 msgid "ALTER TABLE payments ADD failupdate BLOB;" msgstr "" -#: wallet/db.c:348 +#: wallet/db.c:352 msgid "UPDATE payments SET path_secrets = NULL , route_nodes = NULL , route_channels = NULL WHERE status <> 0;" msgstr "" -#: wallet/db.c:355 +#: wallet/db.c:359 msgid "ALTER TABLE channels ADD in_payments_offered INTEGER DEFAULT 0;" msgstr "" -#: wallet/db.c:356 +#: wallet/db.c:360 msgid "ALTER TABLE channels ADD in_payments_fulfilled INTEGER DEFAULT 0;" msgstr "" -#: wallet/db.c:357 +#: wallet/db.c:361 msgid "ALTER TABLE channels ADD in_msatoshi_offered BIGINT DEFAULT 0;" msgstr "" -#: wallet/db.c:358 +#: wallet/db.c:362 msgid "ALTER TABLE channels ADD in_msatoshi_fulfilled BIGINT DEFAULT 0;" msgstr "" -#: wallet/db.c:359 +#: wallet/db.c:363 msgid "ALTER TABLE channels ADD out_payments_offered INTEGER DEFAULT 0;" msgstr "" -#: wallet/db.c:360 +#: wallet/db.c:364 msgid "ALTER TABLE channels ADD out_payments_fulfilled INTEGER DEFAULT 0;" msgstr "" -#: wallet/db.c:361 +#: wallet/db.c:365 msgid "ALTER TABLE channels ADD out_msatoshi_offered BIGINT DEFAULT 0;" msgstr "" -#: wallet/db.c:362 +#: wallet/db.c:366 msgid "ALTER TABLE channels ADD out_msatoshi_fulfilled BIGINT DEFAULT 0;" msgstr "" -#: wallet/db.c:363 +#: wallet/db.c:367 msgid "UPDATE channels SET in_payments_offered = 0, in_payments_fulfilled = 0 , in_msatoshi_offered = 0, in_msatoshi_fulfilled = 0 , out_payments_offered = 0, out_payments_fulfilled = 0 , out_msatoshi_offered = 0, out_msatoshi_fulfilled = 0 ;" msgstr "" -#: wallet/db.c:372 +#: wallet/db.c:376 msgid "ALTER TABLE payments ADD msatoshi_sent BIGINT;" msgstr "" -#: wallet/db.c:373 +#: wallet/db.c:377 msgid "UPDATE payments SET msatoshi_sent = msatoshi;" msgstr "" -#: wallet/db.c:375 +#: wallet/db.c:379 msgid "DELETE FROM utxoset WHERE blockheight IN ( SELECT DISTINCT(blockheight) FROM utxoset LEFT OUTER JOIN blocks on (blockheight = blocks.height) WHERE blocks.hash IS NULL);" msgstr "" -#: wallet/db.c:383 +#: wallet/db.c:387 msgid "ALTER TABLE channels ADD min_possible_feerate INTEGER;" msgstr "" -#: wallet/db.c:384 +#: wallet/db.c:388 msgid "ALTER TABLE channels ADD max_possible_feerate INTEGER;" msgstr "" -#: wallet/db.c:387 +#: wallet/db.c:391 msgid "UPDATE channels SET min_possible_feerate=0, max_possible_feerate=250000;" msgstr "" -#: wallet/db.c:391 +#: wallet/db.c:395 msgid "ALTER TABLE channels ADD msatoshi_to_us_min BIGINT;" msgstr "" -#: wallet/db.c:392 +#: wallet/db.c:396 msgid "ALTER TABLE channels ADD msatoshi_to_us_max BIGINT;" msgstr "" -#: wallet/db.c:393 +#: wallet/db.c:397 msgid "UPDATE channels SET msatoshi_to_us_min = msatoshi_local , msatoshi_to_us_max = msatoshi_local ;" msgstr "" -#: wallet/db.c:402 +#: wallet/db.c:406 msgid "CREATE TABLE transactions ( id BLOB, blockheight INTEGER REFERENCES blocks(height) ON DELETE SET NULL, txindex INTEGER, rawtx BLOB, PRIMARY KEY (id));" msgstr "" -#: wallet/db.c:411 +#: wallet/db.c:415 msgid "ALTER TABLE payments ADD faildetail TEXT;" msgstr "" -#: wallet/db.c:412 +#: wallet/db.c:416 msgid "UPDATE payments SET faildetail = 'unspecified payment failure reason' WHERE status = 2;" msgstr "" -#: wallet/db.c:417 +#: wallet/db.c:421 msgid "CREATE TABLE channeltxs ( id BIGSERIAL, channel_id BIGINT REFERENCES channels(id) ON DELETE CASCADE, type INTEGER, transaction_id BLOB REFERENCES transactions(id) ON DELETE CASCADE, input_num INTEGER, blockheight INTEGER REFERENCES blocks(height) ON DELETE CASCADE, PRIMARY KEY(id));" msgstr "" -#: wallet/db.c:433 +#: wallet/db.c:437 msgid "DELETE FROM blocks WHERE height > (SELECT MIN(first_blocknum) FROM channels);" msgstr "" -#: wallet/db.c:439 +#: wallet/db.c:443 msgid "INSERT INTO blocks (height) VALUES ((SELECT MIN(first_blocknum) FROM channels)) ON CONFLICT(height) DO NOTHING;" msgstr "" -#: wallet/db.c:443 +#: wallet/db.c:447 msgid "DELETE FROM blocks WHERE height IS NULL;" msgstr "" -#: wallet/db.c:445 +#: wallet/db.c:449 msgid "ALTER TABLE invoices ADD description TEXT;" msgstr "" -#: wallet/db.c:447 +#: wallet/db.c:451 msgid "ALTER TABLE payments ADD description TEXT;" msgstr "" -#: wallet/db.c:449 +#: wallet/db.c:453 msgid "ALTER TABLE channels ADD future_per_commitment_point BLOB;" msgstr "" -#: wallet/db.c:451 +#: wallet/db.c:455 msgid "ALTER TABLE channels ADD last_sent_commit BLOB;" msgstr "" -#: wallet/db.c:456 +#: wallet/db.c:460 msgid "CREATE TABLE forwarded_payments ( in_htlc_id BIGINT REFERENCES channel_htlcs(id) ON DELETE SET NULL, out_htlc_id BIGINT REFERENCES channel_htlcs(id) ON DELETE SET NULL, in_channel_scid BIGINT, out_channel_scid BIGINT, in_msatoshi BIGINT, out_msatoshi BIGINT, state INTEGER, UNIQUE(in_htlc_id, out_htlc_id));" msgstr "" -#: wallet/db.c:468 +#: wallet/db.c:472 msgid "ALTER TABLE payments ADD faildirection INTEGER;" msgstr "" -#: wallet/db.c:473 +#: wallet/db.c:477 msgid "ALTER TABLE outputs ADD scriptpubkey BLOB;" msgstr "" -#: wallet/db.c:475 +#: wallet/db.c:479 msgid "ALTER TABLE payments ADD bolt11 TEXT;" msgstr "" -#: wallet/db.c:477 +#: wallet/db.c:481 msgid "ALTER TABLE channels ADD feerate_base INTEGER;" msgstr "" -#: wallet/db.c:478 +#: wallet/db.c:482 msgid "ALTER TABLE channels ADD feerate_ppm INTEGER;" msgstr "" -#: wallet/db.c:480 +#: wallet/db.c:484 msgid "ALTER TABLE channel_htlcs ADD received_time BIGINT" msgstr "" -#: wallet/db.c:481 +#: wallet/db.c:485 msgid "ALTER TABLE forwarded_payments ADD received_time BIGINT" msgstr "" -#: wallet/db.c:482 +#: wallet/db.c:486 msgid "ALTER TABLE forwarded_payments ADD resolved_time BIGINT" msgstr "" -#: wallet/db.c:483 +#: wallet/db.c:487 msgid "ALTER TABLE channels ADD remote_upfront_shutdown_script BLOB;" msgstr "" -#: wallet/db.c:486 +#: wallet/db.c:490 msgid "ALTER TABLE forwarded_payments ADD failcode INTEGER;" msgstr "" -#: wallet/db.c:488 +#: wallet/db.c:492 msgid "ALTER TABLE channels ADD remote_ann_node_sig BLOB;" msgstr "" -#: wallet/db.c:489 +#: wallet/db.c:493 msgid "ALTER TABLE channels ADD remote_ann_bitcoin_sig BLOB;" msgstr "" -#: wallet/db.c:491 +#: wallet/db.c:495 msgid "ALTER TABLE transactions ADD type BIGINT;" msgstr "" -#: wallet/db.c:496 +#: wallet/db.c:500 msgid "ALTER TABLE transactions ADD channel_id BIGINT;" msgstr "" -#: wallet/db.c:498 +#: wallet/db.c:502 msgid "UPDATE channels SET short_channel_id = REPLACE(short_channel_id, ':', 'x') WHERE short_channel_id IS NOT NULL;" msgstr "" -#: wallet/db.c:501 +#: wallet/db.c:505 msgid "UPDATE payments SET failchannel = REPLACE(failchannel, ':', 'x') WHERE failchannel IS NOT NULL;" msgstr "" -#: wallet/db.c:504 +#: wallet/db.c:508 msgid "ALTER TABLE channels ADD COLUMN option_static_remotekey INTEGER DEFAULT 0;" msgstr "" -#: wallet/db.c:506 +#: wallet/db.c:510 msgid "ALTER TABLE vars ADD COLUMN intval INTEGER" msgstr "" -#: wallet/db.c:507 +#: wallet/db.c:511 msgid "ALTER TABLE vars ADD COLUMN blobval BLOB" msgstr "" -#: wallet/db.c:508 +#: wallet/db.c:512 msgid "UPDATE vars SET intval = CAST(val AS INTEGER) WHERE name IN ('bip32_max_index', 'last_processed_block', 'next_pay_index')" msgstr "" -#: wallet/db.c:509 +#: wallet/db.c:513 msgid "UPDATE vars SET blobval = CAST(val AS BLOB) WHERE name = 'genesis_hash'" msgstr "" -#: wallet/db.c:510 +#: wallet/db.c:514 msgid "CREATE TABLE transaction_annotations ( txid BLOB, idx INTEGER, location INTEGER, type INTEGER, channel BIGINT REFERENCES channels(id), UNIQUE(txid, idx));" msgstr "" -#: wallet/db.c:522 +#: wallet/db.c:526 msgid "ALTER TABLE channels ADD shutdown_scriptpubkey_local BLOB;" msgstr "" -#: wallet/db.c:525 +#: wallet/db.c:529 msgid "UPDATE forwarded_payments SET received_time=0 WHERE received_time IS NULL;" msgstr "" -#: wallet/db.c:527 +#: wallet/db.c:531 msgid "ALTER TABLE invoices ADD COLUMN features BLOB DEFAULT '';" msgstr "" -#: wallet/db.c:531 +#: wallet/db.c:535 msgid "CREATE TABLE payments ( id BIGSERIAL, timestamp INTEGER, status INTEGER, payment_hash BLOB, destination BLOB, msatoshi BIGINT, payment_preimage BLOB, path_secrets BLOB, route_nodes BLOB, route_channels BLOB, failonionreply BLOB, faildestperm INTEGER, failindex INTEGER, failcode INTEGER, failnode BLOB, failchannel TEXT, failupdate BLOB, msatoshi_sent BIGINT, faildetail TEXT, description TEXT, faildirection INTEGER, bolt11 TEXT, total_msat BIGINT, partid BIGINT, PRIMARY KEY (id), UNIQUE (payment_hash, partid))" msgstr "" -#: wallet/db.c:558 +#: wallet/db.c:562 msgid "INSERT INTO payments (id, timestamp, status, payment_hash, destination, msatoshi, payment_preimage, path_secrets, route_nodes, route_channels, failonionreply, faildestperm, failindex, failcode, failnode, failchannel, failupdate, msatoshi_sent, faildetail, description, faildirection, bolt11)SELECT id, timestamp, status, payment_hash, destination, msatoshi, payment_preimage, path_secrets, route_nodes, route_channels, failonionreply, faildestperm, failindex, failcode, failnode, failchannel, failupdate, msatoshi_sent, faildetail, description, faildirection, bolt11 FROM temp_payments;" msgstr "" -#: wallet/db.c:603 +#: wallet/db.c:607 msgid "UPDATE payments SET total_msat = msatoshi;" msgstr "" -#: wallet/db.c:604 +#: wallet/db.c:608 msgid "UPDATE payments SET partid = 0;" msgstr "" -#: wallet/db.c:606 +#: wallet/db.c:610 msgid "ALTER TABLE channel_htlcs ADD partid BIGINT;" msgstr "" -#: wallet/db.c:607 +#: wallet/db.c:611 msgid "UPDATE channel_htlcs SET partid = 0;" msgstr "" -#: wallet/db.c:608 +#: wallet/db.c:612 msgid "CREATE TABLE channel_feerates ( channel_id BIGINT REFERENCES channels(id) ON DELETE CASCADE, hstate INTEGER, feerate_per_kw INTEGER, UNIQUE (channel_id, hstate));" msgstr "" -#: wallet/db.c:619 +#: wallet/db.c:623 msgid "INSERT INTO channel_feerates(channel_id, hstate, feerate_per_kw) SELECT id, 4, local_feerate_per_kw FROM channels WHERE funder = 0;" msgstr "" -#: wallet/db.c:623 +#: wallet/db.c:627 msgid "INSERT INTO channel_feerates(channel_id, hstate, feerate_per_kw) SELECT id, 1, remote_feerate_per_kw FROM channels WHERE funder = 0 and local_feerate_per_kw != remote_feerate_per_kw;" msgstr "" -#: wallet/db.c:628 +#: wallet/db.c:632 msgid "INSERT INTO channel_feerates(channel_id, hstate, feerate_per_kw) SELECT id, 14, remote_feerate_per_kw FROM channels WHERE funder = 1;" msgstr "" -#: wallet/db.c:632 +#: wallet/db.c:636 msgid "INSERT INTO channel_feerates(channel_id, hstate, feerate_per_kw) SELECT id, 11, local_feerate_per_kw FROM channels WHERE funder = 1 and local_feerate_per_kw != remote_feerate_per_kw;" msgstr "" -#: wallet/db.c:636 +#: wallet/db.c:640 msgid "INSERT INTO vars (name, intval) VALUES ('data_version', 0);" msgstr "" -#: wallet/db.c:639 +#: wallet/db.c:643 msgid "ALTER TABLE channel_htlcs ADD localfailmsg BLOB;" msgstr "" -#: wallet/db.c:640 +#: wallet/db.c:644 msgid "UPDATE channel_htlcs SET localfailmsg=decode('2002', 'hex') WHERE malformed_onion != 0 AND direction = 1;" msgstr "" -#: wallet/db.c:641 +#: wallet/db.c:645 msgid "ALTER TABLE channels ADD our_funding_satoshi BIGINT DEFAULT 0;" msgstr "" -#: wallet/db.c:642 +#: wallet/db.c:646 msgid "CREATE TABLE penalty_bases ( channel_id BIGINT REFERENCES channels(id) ON DELETE CASCADE, commitnum BIGINT, txid BLOB, outnum INTEGER, amount BIGINT, PRIMARY KEY (channel_id, commitnum));" msgstr "" -#: wallet/db.c:652 +#: wallet/db.c:656 msgid "ALTER TABLE channel_htlcs ADD we_filled INTEGER;" msgstr "" -#: wallet/db.c:654 +#: wallet/db.c:658 msgid "INSERT INTO vars (name, intval) VALUES ('coin_moves_count', 0);" msgstr "" -#: wallet/db.c:656 +#: wallet/db.c:660 msgid "ALTER TABLE outputs ADD reserved_til INTEGER DEFAULT NULL;" msgstr "" -#: wallet/db.c:659 +#: wallet/db.c:663 msgid "ALTER TABLE channels ADD COLUMN option_anchor_outputs INTEGER DEFAULT 0;" msgstr "" -#: wallet/db.c:662 +#: wallet/db.c:666 msgid "ALTER TABLE outputs ADD option_anchor_outputs INTEGER DEFAULT 0;" msgstr "" -#: wallet/db.c:664 +#: wallet/db.c:668 msgid "ALTER TABLE channels ADD full_channel_id BLOB DEFAULT NULL;" msgstr "" -#: wallet/db.c:665 +#: wallet/db.c:669 msgid "ALTER TABLE channels ADD funding_psbt BLOB DEFAULT NULL;" msgstr "" -#: wallet/db.c:667 +#: wallet/db.c:671 msgid "ALTER TABLE channels ADD closer INTEGER DEFAULT 2;" msgstr "" -#: wallet/db.c:668 +#: wallet/db.c:672 msgid "ALTER TABLE channels ADD state_change_reason INTEGER DEFAULT 0;" msgstr "" -#: wallet/db.c:669 +#: wallet/db.c:673 msgid "CREATE TABLE channel_state_changes ( channel_id BIGINT REFERENCES channels(id) ON DELETE CASCADE, timestamp BIGINT, old_state INTEGER, new_state INTEGER, cause INTEGER, message TEXT);" msgstr "" -#: wallet/db.c:677 +#: wallet/db.c:681 msgid "CREATE TABLE offers ( offer_id BLOB, bolt12 TEXT, label TEXT, status INTEGER, PRIMARY KEY (offer_id));" msgstr "" -#: wallet/db.c:685 +#: wallet/db.c:689 msgid "ALTER TABLE invoices ADD COLUMN local_offer_id BLOB DEFAULT NULL REFERENCES offers(offer_id);" msgstr "" -#: wallet/db.c:687 +#: wallet/db.c:691 msgid "ALTER TABLE payments ADD COLUMN local_offer_id BLOB DEFAULT NULL REFERENCES offers(offer_id);" msgstr "" -#: wallet/db.c:688 +#: wallet/db.c:692 msgid "ALTER TABLE channels ADD funding_tx_remote_sigs_received INTEGER DEFAULT 0;" msgstr "" -#: wallet/db.c:691 +#: wallet/db.c:695 msgid "CREATE INDEX forwarded_payments_out_htlc_id ON forwarded_payments (out_htlc_id);" msgstr "" -#: wallet/db.c:693 +#: wallet/db.c:697 msgid "UPDATE channel_htlcs SET malformed_onion = 0 WHERE malformed_onion IS NULL" msgstr "" -#: wallet/db.c:695 +#: wallet/db.c:699 msgid "CREATE INDEX forwarded_payments_state ON forwarded_payments (state)" msgstr "" -#: wallet/db.c:696 +#: wallet/db.c:700 msgid "CREATE TABLE channel_funding_inflights ( channel_id BIGSERIAL REFERENCES channels(id) ON DELETE CASCADE, funding_tx_id BLOB, funding_tx_outnum INTEGER, funding_feerate INTEGER, funding_satoshi BIGINT, our_funding_satoshi BIGINT, funding_psbt BLOB, last_tx BLOB, last_sig BLOB, funding_tx_remote_sigs_received INTEGER, PRIMARY KEY (channel_id, funding_tx_id));" msgstr "" -#: wallet/db.c:710 +#: wallet/db.c:714 msgid "ALTER TABLE channels ADD revocation_basepoint_local BLOB" msgstr "" -#: wallet/db.c:711 +#: wallet/db.c:715 msgid "ALTER TABLE channels ADD payment_basepoint_local BLOB" msgstr "" -#: wallet/db.c:712 +#: wallet/db.c:716 msgid "ALTER TABLE channels ADD htlc_basepoint_local BLOB" msgstr "" -#: wallet/db.c:713 +#: wallet/db.c:717 msgid "ALTER TABLE channels ADD delayed_payment_basepoint_local BLOB" msgstr "" -#: wallet/db.c:714 +#: wallet/db.c:718 msgid "ALTER TABLE channels ADD funding_pubkey_local BLOB" msgstr "" -#: wallet/db.c:717 +#: wallet/db.c:721 msgid "ALTER TABLE channels ADD shutdown_wrong_txid BLOB DEFAULT NULL" msgstr "" -#: wallet/db.c:718 +#: wallet/db.c:722 msgid "ALTER TABLE channels ADD shutdown_wrong_outnum INTEGER DEFAULT NULL" msgstr "" -#: wallet/db.c:721 +#: wallet/db.c:725 msgid "ALTER TABLE channels ADD local_static_remotekey_start BIGINT DEFAULT 0" msgstr "" -#: wallet/db.c:723 +#: wallet/db.c:727 msgid "ALTER TABLE channels ADD remote_static_remotekey_start BIGINT DEFAULT 0" msgstr "" -#: wallet/db.c:726 +#: wallet/db.c:730 msgid "UPDATE channels SET remote_static_remotekey_start = 9223372036854775807, local_static_remotekey_start = 9223372036854775807 WHERE option_static_remotekey = 0" msgstr "" -#: wallet/db.c:731 +#: wallet/db.c:735 msgid "ALTER TABLE channel_funding_inflights ADD lease_commit_sig BLOB DEFAULT NULL" msgstr "" -#: wallet/db.c:732 +#: wallet/db.c:736 msgid "ALTER TABLE channel_funding_inflights ADD lease_chan_max_msat BIGINT DEFAULT NULL" msgstr "" -#: wallet/db.c:733 +#: wallet/db.c:737 msgid "ALTER TABLE channel_funding_inflights ADD lease_chan_max_ppt INTEGER DEFAULT NULL" msgstr "" -#: wallet/db.c:734 +#: wallet/db.c:738 msgid "ALTER TABLE channel_funding_inflights ADD lease_expiry INTEGER DEFAULT 0" msgstr "" -#: wallet/db.c:735 +#: wallet/db.c:739 +msgid "ALTER TABLE channel_funding_inflights ADD lease_blockheight_start INTEGER DEFAULT 0" +msgstr "" + +#: wallet/db.c:740 msgid "ALTER TABLE channels ADD lease_commit_sig BLOB DEFAULT NULL" msgstr "" -#: wallet/db.c:736 +#: wallet/db.c:741 msgid "ALTER TABLE channels ADD lease_chan_max_msat INTEGER DEFAULT NULL" msgstr "" -#: wallet/db.c:737 +#: wallet/db.c:742 msgid "ALTER TABLE channels ADD lease_chan_max_ppt INTEGER DEFAULT NULL" msgstr "" -#: wallet/db.c:738 +#: wallet/db.c:743 msgid "ALTER TABLE channels ADD lease_expiry INTEGER DEFAULT 0" msgstr "" -#: wallet/db.c:965 +#: wallet/db.c:744 +msgid "CREATE TABLE channel_blockheights ( channel_id BIGINT REFERENCES channels(id) ON DELETE CASCADE, hstate INTEGER, blockheight INTEGER, UNIQUE (channel_id, hstate));" +msgstr "" + +#: wallet/db.c:977 msgid "UPDATE vars SET intval = intval + 1 WHERE name = 'data_version' AND intval = ?" msgstr "" -#: wallet/db.c:1065 +#: wallet/db.c:1077 msgid "SELECT version FROM version LIMIT 1" msgstr "" -#: wallet/db.c:1127 +#: wallet/db.c:1139 msgid "UPDATE version SET version=?;" msgstr "" -#: wallet/db.c:1135 +#: wallet/db.c:1147 msgid "INSERT INTO db_upgrades VALUES (?, ?);" msgstr "" -#: wallet/db.c:1147 +#: wallet/db.c:1159 msgid "SELECT intval FROM vars WHERE name = 'data_version'" msgstr "" -#: wallet/db.c:1174 +#: wallet/db.c:1186 msgid "SELECT intval FROM vars WHERE name= ? LIMIT 1" msgstr "" -#: wallet/db.c:1190 +#: wallet/db.c:1202 msgid "UPDATE vars SET intval=? WHERE name=?;" msgstr "" -#: wallet/db.c:1199 +#: wallet/db.c:1211 msgid "INSERT INTO vars (name, intval) VALUES (?, ?);" msgstr "" -#: wallet/db.c:1213 +#: wallet/db.c:1225 msgid "UPDATE channels SET feerate_base = ?, feerate_ppm = ?;" msgstr "" -#: wallet/db.c:1234 +#: wallet/db.c:1246 msgid "UPDATE channels SET our_funding_satoshi = funding_satoshi WHERE funder = 0;" msgstr "" -#: wallet/db.c:1250 +#: wallet/db.c:1262 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:1312 +#: wallet/db.c:1324 msgid "UPDATE outputs SET scriptpubkey = ? WHERE prev_out_tx = ? AND prev_out_index = ?" msgstr "" -#: wallet/db.c:1337 +#: wallet/db.c:1349 msgid "SELECT id, funding_tx_id, funding_tx_outnum FROM channels;" msgstr "" -#: wallet/db.c:1356 +#: wallet/db.c:1368 msgid "UPDATE channels SET full_channel_id = ? WHERE id = ?;" msgstr "" -#: wallet/db.c:1377 +#: wallet/db.c:1389 msgid "SELECT channels.id, peers.node_id FROM channels JOIN peers ON (peers.id = channels.peer_id)" msgstr "" -#: wallet/db.c:1410 +#: wallet/db.c:1422 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:1436 +#: wallet/db.c:1455 +msgid "INSERT INTO channel_blockheights (channel_id, hstate, blockheight) SELECT id, 4, 0 FROM channels WHERE funder = 0;" +msgstr "" + +#: wallet/db.c:1463 +msgid "INSERT INTO channel_blockheights (channel_id, hstate, blockheight) SELECT id, 14, 0 FROM channels WHERE funder = 1;" +msgstr "" + +#: wallet/db.c:1475 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:1503 +#: wallet/db.c:1542 msgid "UPDATE channel_funding_inflights SET last_tx = ? WHERE channel_id = ? AND funding_tx_id = ?;" msgstr "" -#: wallet/db.c:1527 +#: wallet/db.c:1566 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:1594 +#: wallet/db.c:1633 msgid "UPDATE channels SET last_tx = ? WHERE id = ?;" msgstr "" @@ -802,487 +818,499 @@ msgstr "" msgid "SELECT state, payment_key, payment_hash, label, msatoshi, expiry_time, pay_index, msatoshi_received, paid_timestamp, bolt11, description, features, local_offer_id FROM invoices WHERE id = ?;" msgstr "" -#: wallet/wallet.c:65 +#: wallet/wallet.c:66 msgid "SELECT txid, outnum FROM utxoset WHERE spendheight is NULL" msgstr "" -#: wallet/wallet.c:106 wallet/wallet.c:588 +#: wallet/wallet.c:107 wallet/wallet.c:589 msgid "SELECT * from outputs WHERE prev_out_tx=? AND prev_out_index=?" msgstr "" -#: wallet/wallet.c:120 wallet/wallet.c:602 +#: wallet/wallet.c:121 wallet/wallet.c:603 msgid "INSERT INTO outputs ( prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:237 +#: wallet/wallet.c:238 msgid "UPDATE outputs SET status=? WHERE status=? AND prev_out_tx=? AND prev_out_index=?" msgstr "" -#: wallet/wallet.c:245 +#: wallet/wallet.c:246 msgid "UPDATE outputs SET status=? WHERE prev_out_tx=? AND prev_out_index=?" msgstr "" -#: wallet/wallet.c:264 +#: wallet/wallet.c:265 msgid "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til FROM outputs" msgstr "" -#: wallet/wallet.c:281 +#: wallet/wallet.c:282 msgid "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til FROM outputs WHERE status= ? " msgstr "" -#: wallet/wallet.c:319 +#: wallet/wallet.c:320 msgid "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey, reserved_til FROM outputs WHERE channel_id IS NOT NULL AND confirmation_height IS NULL" msgstr "" -#: wallet/wallet.c:356 +#: wallet/wallet.c:357 msgid "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey, reserved_til FROM outputs WHERE prev_out_tx = ? AND prev_out_index = ?" msgstr "" -#: wallet/wallet.c:448 +#: wallet/wallet.c:449 msgid "UPDATE outputs SET status=?, reserved_til=? WHERE prev_out_tx=? AND prev_out_index=?" msgstr "" -#: wallet/wallet.c:537 +#: wallet/wallet.c:538 msgid "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til FROM outputs WHERE status = ? OR (status = ? AND reserved_til <= ?)ORDER BY RANDOM();" msgstr "" -#: wallet/wallet.c:706 +#: wallet/wallet.c:707 msgid "INSERT INTO shachains (min_index, num_valid) VALUES (?, 0);" msgstr "" -#: wallet/wallet.c:750 +#: wallet/wallet.c:751 msgid "UPDATE shachains SET num_valid=?, min_index=? WHERE id=?" msgstr "" -#: wallet/wallet.c:757 +#: wallet/wallet.c:758 msgid "UPDATE shachain_known SET idx=?, hash=? WHERE shachain_id=? AND pos=?" msgstr "" -#: wallet/wallet.c:769 +#: wallet/wallet.c:770 msgid "INSERT INTO shachain_known (shachain_id, pos, idx, hash) VALUES (?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:791 +#: wallet/wallet.c:792 msgid "SELECT min_index, num_valid FROM shachains WHERE id=?" msgstr "" -#: wallet/wallet.c:806 +#: wallet/wallet.c:807 msgid "SELECT idx, hash, pos FROM shachain_known WHERE shachain_id=?" msgstr "" -#: wallet/wallet.c:829 +#: wallet/wallet.c:830 msgid "SELECT id, node_id, address FROM peers WHERE id=?;" msgstr "" -#: wallet/wallet.c:862 +#: wallet/wallet.c:863 msgid "SELECT signature FROM htlc_sigs WHERE channelid = ?" msgstr "" -#: wallet/wallet.c:896 +#: wallet/wallet.c:897 msgid "SELECT remote_ann_node_sig, remote_ann_bitcoin_sig FROM channels WHERE id = ?" msgstr "" -#: wallet/wallet.c:940 +#: wallet/wallet.c:941 msgid "SELECT hstate, feerate_per_kw FROM channel_feerates WHERE channel_id = ?" msgstr "" -#: wallet/wallet.c:973 -msgid "INSERT INTO channel_funding_inflights ( channel_id, funding_tx_id, funding_tx_outnum, funding_feerate, funding_satoshi, our_funding_satoshi, funding_psbt, last_tx, last_sig) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);" +#: wallet/wallet.c:977 +msgid "SELECT hstate, blockheight FROM channel_blockheights WHERE channel_id = ?" +msgstr "" + +#: wallet/wallet.c:1010 +msgid "INSERT INTO channel_funding_inflights ( channel_id, funding_tx_id, funding_tx_outnum, funding_feerate, funding_satoshi, our_funding_satoshi, funding_psbt, last_tx, last_sig, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt, lease_expiry, lease_blockheight_start) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:1008 +#: wallet/wallet.c:1066 msgid "UPDATE channel_funding_inflights SET funding_psbt=?, funding_tx_remote_sigs_received=? WHERE channel_id=? AND funding_tx_id=? AND funding_tx_outnum=?" msgstr "" -#: wallet/wallet.c:1031 +#: wallet/wallet.c:1089 msgid "DELETE FROM channel_funding_inflights WHERE channel_id = ?" msgstr "" -#: wallet/wallet.c:1098 -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, lease_expiry, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt FROM channel_funding_inflights WHERE channel_id = ? ORDER BY funding_feerate" +#: wallet/wallet.c:1159 +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, lease_expiry, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt, lease_blockheight_start FROM channel_funding_inflights WHERE channel_id = ? ORDER BY funding_feerate" msgstr "" -#: wallet/wallet.c:1350 +#: wallet/wallet.c:1427 msgid "SELECT id FROM channels ORDER BY id DESC LIMIT 1;" msgstr "" -#: wallet/wallet.c:1367 +#: wallet/wallet.c:1444 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, lease_expiry, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt FROM channels WHERE state != ?;" msgstr "" -#: wallet/wallet.c:1479 +#: wallet/wallet.c:1556 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:1485 +#: wallet/wallet.c:1562 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:1491 +#: wallet/wallet.c:1568 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:1497 +#: wallet/wallet.c:1574 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:1542 +#: wallet/wallet.c:1619 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:1571 +#: wallet/wallet.c:1648 msgid "SELECT MIN(height), MAX(height) FROM blocks;" msgstr "" -#: wallet/wallet.c:1593 +#: wallet/wallet.c:1670 msgid "INSERT INTO channel_configs DEFAULT VALUES;" msgstr "" -#: wallet/wallet.c:1605 +#: wallet/wallet.c:1682 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:1629 +#: wallet/wallet.c:1706 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:1663 +#: wallet/wallet.c:1740 msgid "UPDATE channels SET remote_ann_node_sig=?, remote_ann_bitcoin_sig=? WHERE id=?" msgstr "" -#: wallet/wallet.c:1682 +#: wallet/wallet.c:1759 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=?, lease_expiry=?, lease_commit_sig=?, lease_chan_max_msat=?, lease_chan_max_ppt=? WHERE id=?" msgstr "" -#: wallet/wallet.c:1791 +#: wallet/wallet.c:1868 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:1818 +#: wallet/wallet.c:1895 msgid "DELETE FROM channel_feerates WHERE channel_id=?" msgstr "" -#: wallet/wallet.c:1828 +#: wallet/wallet.c:1905 msgid "INSERT INTO channel_feerates VALUES(?, ?, ?)" msgstr "" -#: wallet/wallet.c:1845 +#: wallet/wallet.c:1914 +msgid "DELETE FROM channel_blockheights WHERE channel_id=?" +msgstr "" + +#: wallet/wallet.c:1924 +msgid "INSERT INTO channel_blockheights VALUES(?, ?, ?)" +msgstr "" + +#: wallet/wallet.c:1941 msgid "UPDATE channels SET last_sent_commit=? WHERE id=?" msgstr "" -#: wallet/wallet.c:1868 +#: wallet/wallet.c:1964 msgid "INSERT INTO channel_state_changes ( channel_id, timestamp, old_state, new_state, cause, message) VALUES (?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:1896 +#: wallet/wallet.c:1992 msgid "SELECT timestamp, old_state, new_state, cause, message FROM channel_state_changes WHERE channel_id = ? ORDER BY timestamp ASC;" msgstr "" -#: wallet/wallet.c:1925 +#: wallet/wallet.c:2021 msgid "SELECT id FROM peers WHERE node_id = ?" msgstr "" -#: wallet/wallet.c:1937 +#: wallet/wallet.c:2033 msgid "UPDATE peers SET address = ? WHERE id = ?" msgstr "" -#: wallet/wallet.c:1946 +#: wallet/wallet.c:2042 msgid "INSERT INTO peers (node_id, address) VALUES (?, ?);" msgstr "" -#: wallet/wallet.c:1967 +#: wallet/wallet.c:2063 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:2008 +#: wallet/wallet.c:2104 msgid "DELETE FROM channel_htlcs WHERE channel_id=?" msgstr "" -#: wallet/wallet.c:2014 +#: wallet/wallet.c:2110 msgid "DELETE FROM htlc_sigs WHERE channelid=?" msgstr "" -#: wallet/wallet.c:2020 +#: wallet/wallet.c:2116 msgid "DELETE FROM channeltxs WHERE channel_id=?" msgstr "" -#: wallet/wallet.c:2027 +#: wallet/wallet.c:2123 msgid "DELETE FROM channel_funding_inflights WHERE channel_id=?" msgstr "" -#: wallet/wallet.c:2033 +#: wallet/wallet.c:2129 msgid "DELETE FROM shachains WHERE id IN ( SELECT shachain_remote_id FROM channels WHERE channels.id=?)" msgstr "" -#: wallet/wallet.c:2043 +#: wallet/wallet.c:2139 msgid "UPDATE channels SET state=?, peer_id=? WHERE channels.id=?" msgstr "" -#: wallet/wallet.c:2057 +#: wallet/wallet.c:2153 msgid "SELECT * FROM channels WHERE peer_id = ?;" msgstr "" -#: wallet/wallet.c:2065 +#: wallet/wallet.c:2161 msgid "DELETE FROM peers WHERE id=?" msgstr "" -#: wallet/wallet.c:2076 +#: wallet/wallet.c:2172 msgid "UPDATE outputs SET confirmation_height = ? WHERE prev_out_tx = ?" msgstr "" -#: wallet/wallet.c:2179 +#: wallet/wallet.c:2275 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:2232 +#: wallet/wallet.c:2328 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:2293 +#: wallet/wallet.c:2389 msgid "UPDATE channel_htlcs SET hstate=?, payment_key=?, malformed_onion=?, failuremsg=?, localfailmsg=?, we_filled=? WHERE id=?" msgstr "" -#: wallet/wallet.c:2510 +#: wallet/wallet.c:2606 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:2557 +#: wallet/wallet.c:2653 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:2688 +#: wallet/wallet.c:2784 msgid "SELECT channel_id, direction, cltv_expiry, channel_htlc_id, payment_hash FROM channel_htlcs WHERE channel_id = ?;" msgstr "" -#: wallet/wallet.c:2722 +#: wallet/wallet.c:2818 msgid "DELETE FROM channel_htlcs WHERE direction = ? AND origin_htlc = ? AND payment_hash = ? AND partid = ?;" msgstr "" -#: wallet/wallet.c:2775 +#: wallet/wallet.c:2871 msgid "SELECT status FROM payments WHERE payment_hash=? AND partid = ?;" msgstr "" -#: wallet/wallet.c:2793 +#: wallet/wallet.c:2889 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:2882 +#: wallet/wallet.c:2978 msgid "DELETE FROM payments WHERE payment_hash = ? AND partid = ?" msgstr "" -#: wallet/wallet.c:2896 +#: wallet/wallet.c:2992 msgid "DELETE FROM payments WHERE payment_hash = ?" msgstr "" -#: wallet/wallet.c:2997 +#: wallet/wallet.c:3093 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:3047 +#: wallet/wallet.c:3143 msgid "UPDATE payments SET status=? WHERE payment_hash=? AND partid=?" msgstr "" -#: wallet/wallet.c:3057 +#: wallet/wallet.c:3153 msgid "UPDATE payments SET payment_preimage=? WHERE payment_hash=? AND partid=?" msgstr "" -#: wallet/wallet.c:3067 +#: wallet/wallet.c:3163 msgid "UPDATE payments SET path_secrets = NULL , route_nodes = NULL , route_channels = NULL WHERE payment_hash = ? AND partid = ?;" msgstr "" -#: wallet/wallet.c:3099 +#: wallet/wallet.c:3195 msgid "SELECT failonionreply, faildestperm, failindex, failcode, failnode, failchannel, failupdate, faildetail, faildirection FROM payments WHERE payment_hash=? AND partid=?;" msgstr "" -#: wallet/wallet.c:3166 +#: wallet/wallet.c:3262 msgid "UPDATE payments SET failonionreply=? , faildestperm=? , failindex=? , failcode=? , failnode=? , failchannel=? , failupdate=? , faildetail=? , faildirection=? WHERE payment_hash=? AND partid=?;" msgstr "" -#: wallet/wallet.c:3225 +#: wallet/wallet.c:3321 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:3248 +#: wallet/wallet.c:3344 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:3299 +#: wallet/wallet.c:3395 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:3344 +#: wallet/wallet.c:3440 msgid "DELETE FROM htlc_sigs WHERE channelid = ?" msgstr "" -#: wallet/wallet.c:3351 +#: wallet/wallet.c:3447 msgid "INSERT INTO htlc_sigs (channelid, signature) VALUES (?, ?)" msgstr "" -#: wallet/wallet.c:3363 +#: wallet/wallet.c:3459 msgid "SELECT blobval FROM vars WHERE name='genesis_hash'" msgstr "" -#: wallet/wallet.c:3387 +#: wallet/wallet.c:3483 msgid "INSERT INTO vars (name, blobval) VALUES ('genesis_hash', ?);" msgstr "" -#: wallet/wallet.c:3405 +#: wallet/wallet.c:3501 msgid "SELECT txid, outnum FROM utxoset WHERE spendheight < ?" msgstr "" -#: wallet/wallet.c:3417 +#: wallet/wallet.c:3513 msgid "DELETE FROM utxoset WHERE spendheight < ?" msgstr "" -#: wallet/wallet.c:3425 wallet/wallet.c:3539 +#: wallet/wallet.c:3521 wallet/wallet.c:3635 msgid "INSERT INTO blocks (height, hash, prev_hash) VALUES (?, ?, ?);" msgstr "" -#: wallet/wallet.c:3444 +#: wallet/wallet.c:3540 msgid "DELETE FROM blocks WHERE hash = ?" msgstr "" -#: wallet/wallet.c:3450 +#: wallet/wallet.c:3546 msgid "SELECT * FROM blocks WHERE height >= ?;" msgstr "" -#: wallet/wallet.c:3459 +#: wallet/wallet.c:3555 msgid "DELETE FROM blocks WHERE height > ?" msgstr "" -#: wallet/wallet.c:3471 +#: wallet/wallet.c:3567 msgid "UPDATE outputs SET spend_height = ?, status = ? WHERE prev_out_tx = ? AND prev_out_index = ?" msgstr "" -#: wallet/wallet.c:3489 +#: wallet/wallet.c:3585 msgid "UPDATE utxoset SET spendheight = ? WHERE txid = ? AND outnum = ?" msgstr "" -#: wallet/wallet.c:3512 wallet/wallet.c:3550 +#: wallet/wallet.c:3608 wallet/wallet.c:3646 msgid "INSERT INTO utxoset ( txid, outnum, blockheight, spendheight, txindex, scriptpubkey, satoshis) VALUES(?, ?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:3576 +#: wallet/wallet.c:3672 msgid "SELECT height FROM blocks WHERE height = ?" msgstr "" -#: wallet/wallet.c:3589 +#: wallet/wallet.c:3685 msgid "SELECT txid, spendheight, scriptpubkey, satoshis FROM utxoset WHERE blockheight = ? AND txindex = ? AND outnum = ? AND spendheight IS NULL" msgstr "" -#: wallet/wallet.c:3631 +#: wallet/wallet.c:3727 msgid "SELECT blockheight, txindex, outnum FROM utxoset WHERE spendheight = ?" msgstr "" -#: wallet/wallet.c:3662 wallet/wallet.c:3822 +#: wallet/wallet.c:3758 wallet/wallet.c:3918 msgid "SELECT blockheight FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3672 +#: wallet/wallet.c:3768 msgid "INSERT INTO transactions ( id, blockheight, txindex, rawtx) VALUES (?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:3693 +#: wallet/wallet.c:3789 msgid "UPDATE transactions SET blockheight = ?, txindex = ? WHERE id = ?" msgstr "" -#: wallet/wallet.c:3710 +#: wallet/wallet.c:3806 msgid "INSERT INTO transaction_annotations (txid, idx, location, type, channel) VALUES (?, ?, ?, ?, ?) ON CONFLICT(txid,idx) DO NOTHING;" msgstr "" -#: wallet/wallet.c:3742 +#: wallet/wallet.c:3838 msgid "SELECT type, channel_id FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3758 +#: wallet/wallet.c:3854 msgid "UPDATE transactions SET type = ?, channel_id = ? WHERE id = ?" msgstr "" -#: wallet/wallet.c:3777 +#: wallet/wallet.c:3873 msgid "SELECT type FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3800 +#: wallet/wallet.c:3896 msgid "SELECT rawtx FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3846 +#: wallet/wallet.c:3942 msgid "SELECT blockheight, txindex FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3874 +#: wallet/wallet.c:3970 msgid "SELECT id FROM transactions WHERE blockheight=?" msgstr "" -#: wallet/wallet.c:3893 +#: wallet/wallet.c:3989 msgid "INSERT INTO channeltxs ( channel_id, type, transaction_id, input_num, blockheight) VALUES (?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:3917 +#: wallet/wallet.c:4013 msgid "SELECT DISTINCT(channel_id) FROM channeltxs WHERE type = ?;" msgstr "" -#: wallet/wallet.c:3938 +#: wallet/wallet.c:4034 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:3983 +#: wallet/wallet.c:4079 msgid "UPDATE forwarded_payments SET in_msatoshi=?, out_msatoshi=?, state=?, resolved_time=?, failcode=? WHERE in_htlc_id=?" msgstr "" -#: wallet/wallet.c:4041 +#: wallet/wallet.c:4137 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:4100 +#: wallet/wallet.c:4196 msgid "SELECT CAST(COALESCE(SUM(in_msatoshi - out_msatoshi), 0) AS BIGINT)FROM forwarded_payments WHERE state = ?;" msgstr "" -#: wallet/wallet.c:4149 +#: wallet/wallet.c:4245 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:4271 +#: wallet/wallet.c:4367 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:4365 +#: wallet/wallet.c:4461 msgid "INSERT INTO penalty_bases ( channel_id, commitnum, txid, outnum, amount) VALUES (?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:4390 +#: wallet/wallet.c:4486 msgid "SELECT commitnum, txid, outnum, amount FROM penalty_bases WHERE channel_id = ?" msgstr "" -#: wallet/wallet.c:4414 +#: wallet/wallet.c:4510 msgid "DELETE FROM penalty_bases WHERE channel_id = ? AND commitnum = ?" msgstr "" -#: wallet/wallet.c:4432 +#: wallet/wallet.c:4528 msgid "SELECT 1 FROM offers WHERE offer_id = ?;" msgstr "" -#: wallet/wallet.c:4445 +#: wallet/wallet.c:4541 msgid "INSERT INTO offers ( offer_id, bolt12, label, status) VALUES (?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:4472 +#: wallet/wallet.c:4568 msgid "SELECT bolt12, label, status FROM offers WHERE offer_id = ?;" msgstr "" -#: wallet/wallet.c:4500 +#: wallet/wallet.c:4596 msgid "SELECT offer_id FROM offers;" msgstr "" -#: wallet/wallet.c:4526 +#: wallet/wallet.c:4622 msgid "UPDATE offers SET status=? WHERE offer_id = ?;" msgstr "" -#: wallet/wallet.c:4537 +#: wallet/wallet.c:4633 msgid "UPDATE invoices SET state=? WHERE state=? AND local_offer_id = ?;" msgstr "" -#: wallet/wallet.c:4565 +#: wallet/wallet.c:4661 msgid "SELECT status FROM offers WHERE offer_id = ?;" msgstr "" @@ -1294,11 +1322,11 @@ msgstr "" msgid "not a valid SQL statement" msgstr "" -#: wallet/test/run-wallet.c:1451 +#: wallet/test/run-wallet.c:1483 msgid "SELECT COUNT(1) FROM channel_funding_inflights WHERE channel_id = ?;" msgstr "" -#: wallet/test/run-wallet.c:1653 +#: wallet/test/run-wallet.c:1696 msgid "INSERT INTO channels (id) VALUES (1);" msgstr "" -# SHA256STAMP:916e655abfda9823c699c33992127a55f070317c2f7f89be918dc55a1d2e685e +# SHA256STAMP:b2158376af794319787cce0ea1066b6778edb5a1e04841e539a79bc69b59db46 diff --git a/wallet/test/Makefile b/wallet/test/Makefile index 8c60d6c8e5d8..7526ec2321e6 100644 --- a/wallet/test/Makefile +++ b/wallet/test/Makefile @@ -8,6 +8,7 @@ ALL_TEST_PROGRAMS += $(WALLET_TEST_PROGRAMS) WALLET_TEST_COMMON_OBJS := \ common/amount.o \ common/base32.o \ + common/blockheight_states.o \ common/derive_basepoints.o \ common/htlc_state.o \ common/htlc_wire.o \ diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index f8f2672fc68d..0f3acfa7ce48 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -1184,6 +1184,15 @@ static bool channel_inflightseq(struct channel_inflight *i1, &i2->last_sig, sizeof(i2->last_sig))); CHECK(bitcoin_tx_eq(i1->last_tx, i2->last_tx)); + CHECK(!i1->lease_commit_sig == !i2->lease_commit_sig); + if (i1->lease_commit_sig) + CHECK(memeq(i1->lease_commit_sig, sizeof(*i1->lease_commit_sig), + i2->lease_commit_sig, sizeof(*i2->lease_commit_sig))); + CHECK(i1->lease_expiry == i2->lease_expiry); + CHECK(i1->lease_chan_max_msat == i2->lease_chan_max_msat); + CHECK(i1->lease_chan_max_ppt == i2->lease_chan_max_ppt); + CHECK(i1->lease_blockheight_start == i2->lease_blockheight_start); + return true; } @@ -1254,6 +1263,27 @@ static bool channelseq(struct channel *c1, struct channel *c2) CHECK(c1->last_was_revoke == c2->last_was_revoke); + CHECK(!c1->lease_commit_sig == !c2->lease_commit_sig); + if (c1->lease_commit_sig) + CHECK(memeq(c1->lease_commit_sig, sizeof(*c1->lease_commit_sig), + c2->lease_commit_sig, sizeof(*c2->lease_commit_sig))); + + CHECK(c1->lease_chan_max_msat == c2->lease_chan_max_msat); + CHECK(c1->lease_chan_max_ppt == c2->lease_chan_max_ppt); + CHECK(c1->lease_expiry == c2->lease_expiry); + + CHECK(height_states_valid(c1->blockheight_states, c1->opener)); + CHECK(height_states_valid(c2->blockheight_states, c2->opener)); + for (enum htlc_state i = 0; i < ARRAY_SIZE(c1->blockheight_states->height); + i++) { + if (c1->blockheight_states->height[i] == NULL) { + CHECK(c2->blockheight_states->height[i] == NULL); + } else { + CHECK(*c1->blockheight_states->height[i] + == *c2->blockheight_states->height[i]); + } + } + i1 = list_top(&c1->inflights, struct channel_inflight, list); i2 = list_top(&c2->inflights, struct channel_inflight, list); CHECK((i1 != NULL) == (i2 != NULL)); @@ -1304,7 +1334,7 @@ static bool test_channel_crud(struct lightningd *ld, const tal_t *ctx) secp256k1_ecdsa_signature *node_sig1 = tal(w, secp256k1_ecdsa_signature); secp256k1_ecdsa_signature *bitcoin_sig1 = tal(w, secp256k1_ecdsa_signature); secp256k1_ecdsa_signature *node_sig2, *bitcoin_sig2; - u32 feerate; + u32 feerate, blockheight; bool load; memset(&c1, 0, sizeof(c1)); @@ -1320,6 +1350,8 @@ static bool test_channel_crud(struct lightningd *ld, const tal_t *ctx) node_id_from_pubkey(&id, &pk); feerate = 31337; c1.fee_states = new_fee_states(w, c1.opener, &feerate); + blockheight = 10010; + c1.blockheight_states = new_height_states(w, c1.opener, &blockheight); mempat(scriptpubkey, tal_count(scriptpubkey)); c1.first_blocknum = 1; parse_wireaddr_internal("localhost:1234", &addr, 0, false, false, false, @@ -1478,7 +1510,8 @@ static bool test_channel_inflight_crud(struct lightningd *ld, const tal_t *ctx) struct wally_psbt *funding_psbt; struct channel_info *channel_info = tal(w, struct channel_info); struct basepoints basepoints; - u32 feerate; + secp256k1_ecdsa_signature *lease_commit_sig; + u32 feerate, lease_blockheight_start; u64 dbid; pubkey_from_der(tal_hexdata(w, "02a1633cafcc01ebfb6d78e39f687a1f0995c62fc95f51ead10a02ee0be551b5dc", 66), 33, &pk); @@ -1493,12 +1526,17 @@ static bool test_channel_inflight_crud(struct lightningd *ld, const tal_t *ctx) our_sats = AMOUNT_SAT(3333333); mempat(&sig.s, sizeof(sig.s)); mempat(&cid, sizeof(struct channel_id)); + + lease_commit_sig = tal(w, secp256k1_ecdsa_signature); + mempat(lease_commit_sig, sizeof(*lease_commit_sig)); + sig.sighash_type = SIGHASH_ALL; /* last_tx taken from BOLT #3 */ last_tx = bitcoin_tx_from_hex(w, "02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8003a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de843110ae8f6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e040047304402206a2679efa3c7aaffd2a447fd0df7aba8792858b589750f6a1203f9259173198a022008d52a0e77a99ab533c36206cb15ad7aeb2aa72b93d4b571e728cb5ec2f6fe260147304402206d6cb93969d39177a09d5d45b583f34966195b77c7e585cf47ac5cce0c90cefb022031d71ae4e33a4e80df7f981d696fbdee517337806a3c7138b7491e2cbb077a0e01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220", strlen("02000000000101bef67e4e2fb9ddeeb3461973cd4c62abb35050b1add772995b820b584a488489000000000038b02b8003a00f0000000000002200208c48d15160397c9731df9bc3b236656efb6665fbfe92b4a6878e88a499f741c4c0c62d0000000000160014ccf1af2f2aabee14bb40fa3851ab2301de843110ae8f6a00000000002200204adb4e2f00643db396dd120d4e7dc17625f5f2c11a40d857accc862d6b7dd80e040047304402206a2679efa3c7aaffd2a447fd0df7aba8792858b589750f6a1203f9259173198a022008d52a0e77a99ab533c36206cb15ad7aeb2aa72b93d4b571e728cb5ec2f6fe260147304402206d6cb93969d39177a09d5d45b583f34966195b77c7e585cf47ac5cce0c90cefb022031d71ae4e33a4e80df7f981d696fbdee517337806a3c7138b7491e2cbb077a0e01475221023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb21030e9f7b623d2ccc7c9bd44d66d5ce21ce504c0acf6385a132cec6d3c39fa711c152ae3e195220")); funding_psbt = psbt_from_b64(w, "cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEHakcwRAIgR1lmF5fAGwNrJZKJSGhiGDR9iYZLcZ4ff89X0eURZYcCIFMJ6r9Wqk2Ikf/REf3xM286KdqGbX+EhtdVRs7tr5MZASEDXNxh/HupccC1AaZGoqg7ECy0OIEhfKaC3Ibi1z+ogpIAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIAAAA", strlen("cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEHakcwRAIgR1lmF5fAGwNrJZKJSGhiGDR9iYZLcZ4ff89X0eURZYcCIFMJ6r9Wqk2Ikf/REf3xM286KdqGbX+EhtdVRs7tr5MZASEDXNxh/HupccC1AaZGoqg7ECy0OIEhfKaC3Ibi1z+ogpIAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIAAAA")); feerate = 192838; + lease_blockheight_start = 101010; memset(&our_config, 1, sizeof(struct channel_config)); our_config.id = 0; memset(&txid, 1, sizeof(txid)); @@ -1541,8 +1579,12 @@ static bool test_channel_inflight_crud(struct lightningd *ld, const tal_t *ctx) &pk, NULL, 1000, 100, NULL, 0, 0, true, - LOCAL, REASON_UNKNOWN, NULL, - 100, NULL, + LOCAL, REASON_UNKNOWN, + NULL, + new_height_states(w, LOCAL, + &lease_blockheight_start), + 100, + lease_commit_sig, 7777, 22); db_begin_transaction(w->db); CHECK(!wallet_err); @@ -1560,7 +1602,7 @@ static bool test_channel_inflight_crud(struct lightningd *ld, const tal_t *ctx) funding_psbt, last_tx, sig, - 1, NULL, 2, 4); + 1, lease_commit_sig, 2, 4, 22); /* do inflights get correctly added to the channel? */ wallet_inflight_add(w, inflight); @@ -1582,12 +1624,13 @@ static bool test_channel_inflight_crud(struct lightningd *ld, const tal_t *ctx) funding_psbt, last_tx, sig, - 1, NULL, 2, 4); + 0, NULL, 0, 0, 0); wallet_inflight_add(w, inflight); CHECK_MSG(c2 = wallet_channel_load(w, chan->dbid), tal_fmt(w, "Load from DB")); CHECK_MSG(channelseq(chan, c2), "Compare loaded with saved (v2)"); CHECK_MSG(count_inflights(w, chan->dbid) == 2, "inflights exist"); + tal_free(c2); /* Update the PSBT for both inflights, check that are updated diff --git a/wallet/wallet.c b/wallet/wallet.c index 7be2547f2fd4..fd86fd208245 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -966,21 +967,63 @@ static struct fee_states *wallet_channel_fee_states_load(struct wallet *w, return fee_states; } +static struct height_states *wallet_channel_height_states_load(struct wallet *w, + const u64 id, + enum side opener) +{ + struct height_states *states; + struct db_stmt *stmt; + + stmt = db_prepare_v2(w->db, SQL("SELECT hstate, blockheight FROM channel_blockheights WHERE channel_id = ?")); + db_bind_u64(stmt, 0, id); + db_query_prepared(stmt); + + /* Start with blank slate. */ + states = new_height_states(w, opener, NULL); + while (db_step(stmt)) { + enum htlc_state hstate = db_column_int(stmt, 0); + u32 blockheight = db_column_int(stmt, 1); + + if (states->height[hstate] != NULL) { + log_broken(w->log, + "duplicate channel_blockheights for %s id %"PRIu64, + htlc_state_name(hstate), id); + states = tal_free(states); + break; + } + states->height[hstate] = tal_dup(states, u32, &blockheight); + } + tal_free(stmt); + + if (states && !height_states_valid(states, opener)) { + log_broken(w->log, + "invalid channel_blockheight for id %"PRIu64, id); + states = tal_free(states); + } + return states; +} + void wallet_inflight_add(struct wallet *w, struct channel_inflight *inflight) { struct db_stmt *stmt; stmt = db_prepare_v2(w->db, SQL("INSERT INTO channel_funding_inflights (" - " channel_id" - ", funding_tx_id" - ", funding_tx_outnum" - ", funding_feerate" - ", funding_satoshi" - ", our_funding_satoshi" - ", funding_psbt" - ", last_tx" - ", last_sig" - ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);")); + " channel_id" // 0 + ", funding_tx_id" // 1 + ", funding_tx_outnum" // 2 + ", funding_feerate" // 3 + ", funding_satoshi" // 4 + ", our_funding_satoshi" // 5 + ", funding_psbt" // 6 + ", last_tx" // 7 + ", last_sig" // 8 + ", lease_commit_sig" // 9 + ", lease_chan_max_msat" // 10 + ", lease_chan_max_ppt" // 11 + ", lease_expiry" // 12 + ", lease_blockheight_start" // 13 + ") VALUES (" + "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);")); db_bind_u64(stmt, 0, inflight->channel->dbid); db_bind_txid(stmt, 1, &inflight->funding->txid); @@ -991,6 +1034,21 @@ void wallet_inflight_add(struct wallet *w, struct channel_inflight *inflight) db_bind_psbt(stmt, 6, inflight->funding_psbt); db_bind_psbt(stmt, 7, inflight->last_tx->psbt); db_bind_signature(stmt, 8, &inflight->last_sig.s); + + if (inflight->lease_expiry != 0) { + db_bind_signature(stmt, 9, inflight->lease_commit_sig); + db_bind_int(stmt, 10, inflight->lease_chan_max_msat); + db_bind_int(stmt, 11, inflight->lease_chan_max_ppt); + db_bind_int(stmt, 12, inflight->lease_expiry); + db_bind_int(stmt, 13, inflight->lease_blockheight_start); + } else { + db_bind_null(stmt, 9); + db_bind_null(stmt, 10); + db_bind_null(stmt, 11); + db_bind_null(stmt, 12); + db_bind_null(stmt, 13); + } + db_exec_prepared_v2(stmt); assert(!stmt->error); tal_free(stmt); @@ -1049,7 +1107,7 @@ wallet_stmt2inflight(struct wallet *w, struct db_stmt *stmt, struct channel_inflight *inflight; secp256k1_ecdsa_signature *lease_commit_sig; - u32 lease_chan_max_msat; + u32 lease_chan_max_msat, lease_blockheight_start; u16 lease_chan_max_ppt; db_column_txid(stmt, 0, &funding_txid); @@ -1065,10 +1123,12 @@ wallet_stmt2inflight(struct wallet *w, struct db_stmt *stmt, db_column_signature(stmt, 10, lease_commit_sig); lease_chan_max_msat = db_column_int(stmt, 11); lease_chan_max_ppt = db_column_int(stmt, 12); + lease_blockheight_start = db_column_int(stmt, 13); } else { lease_commit_sig = NULL; lease_chan_max_msat = 0; lease_chan_max_ppt = 0; + lease_blockheight_start = 0; } inflight = new_inflight(chan, funding_txid, @@ -1082,7 +1142,8 @@ wallet_stmt2inflight(struct wallet *w, struct db_stmt *stmt, db_column_int(stmt, 9), lease_commit_sig, lease_chan_max_msat, - lease_chan_max_ppt); + lease_chan_max_ppt, + lease_blockheight_start); /* Pull out the serialized tx-sigs-received-ness */ inflight->remote_tx_sigs = db_column_int(stmt, 8); @@ -1109,6 +1170,7 @@ static bool wallet_channel_load_inflights(struct wallet *w, ", lease_commit_sig" // 10 ", lease_chan_max_msat" // 11 ", lease_chan_max_ppt" // 12 + ", lease_blockheight_start" // 13 " FROM channel_funding_inflights" " WHERE channel_id = ?" // ?0 " ORDER BY funding_feerate")); @@ -1137,6 +1199,7 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm bool ok = true; struct channel_info channel_info; struct fee_states *fee_states; + struct height_states *height_states; struct short_channel_id *scid; struct channel_id cid; struct channel *chan; @@ -1241,6 +1304,19 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm return NULL; } + /* Blockheight states for the channel! */ + height_states + = wallet_channel_height_states_load(w, + db_column_u64(stmt, 0), + db_column_int(stmt, 7)); + if (!height_states) + ok = false; + + if (!ok) { + tal_free(height_states); + return NULL; + } + final_key_idx = db_column_u64(stmt, 31); if (final_key_idx < 0) { tal_free(fee_states); @@ -1330,6 +1406,7 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm db_column_int(stmt, 51), db_column_int(stmt, 52), shutdown_wrong_funding, + take(height_states), db_column_int(stmt, 60), lease_commit_sig, lease_chan_max_msat, @@ -1833,6 +1910,25 @@ void wallet_channel_save(struct wallet *w, struct channel *chan) db_exec_prepared_v2(take(stmt)); } + /* FIXME: Updates channel_blockheights by discarding and rewriting. */ + stmt = db_prepare_v2(w->db, SQL("DELETE FROM channel_blockheights " + "WHERE channel_id=?")); + db_bind_u64(stmt, 0, chan->dbid); + db_exec_prepared_v2(take(stmt)); + + for (enum htlc_state i = 0; + i < ARRAY_SIZE(chan->blockheight_states->height); + i++) { + if (!chan->blockheight_states->height[i]) + continue; + stmt = db_prepare_v2(w->db, SQL("INSERT INTO channel_blockheights " + " VALUES(?, ?, ?)")); + db_bind_u64(stmt, 0, chan->dbid); + db_bind_int(stmt, 1, i); + db_bind_int(stmt, 2, *chan->blockheight_states->height[i]); + db_exec_prepared_v2(take(stmt)); + } + /* If we have a last_sent_commit, store it */ last_sent_commit = tal_arr(tmpctx, u8, 0); for (size_t i = 0; i < tal_count(chan->last_sent_commit); i++) diff --git a/wire/common_wiregen.c b/wire/common_wiregen.c index 1355150fd480..cca2e92611da 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:a747ee0bc8a91c00e719bae883b505d6e7c85b33165a9156a571a0aa171a7256 +// SHA256STAMP:dae50cbf444bf43c76720df0cf0a89b4360ff576307f88d54e55696c034c1266 diff --git a/wire/common_wiregen.h b/wire/common_wiregen.h index 9efd995e40c3..5cd2b3cc572f 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:a747ee0bc8a91c00e719bae883b505d6e7c85b33165a9156a571a0aa171a7256 +// SHA256STAMP:dae50cbf444bf43c76720df0cf0a89b4360ff576307f88d54e55696c034c1266 From 2812b24bd9d32a4243a856465f16ed6aff292614 Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 22 Jun 2021 16:47:33 -0500 Subject: [PATCH 32/56] channel: wire blockheight updates from channeld in to database --- channeld/channeld.c | 18 +++++++++++++----- channeld/channeld_wire.csv | 3 +++ channeld/channeld_wiregen.c | 20 +++++++++++++------- channeld/channeld_wiregen.h | 14 +++++++------- common/initial_channel.c | 6 ++++++ common/initial_channel.h | 7 +++++++ lightningd/peer_htlcs.c | 26 ++++++++++++++++++++++---- wallet/db_postgres_sqlgen.c | 2 +- wallet/db_sqlite3_sqlgen.c | 2 +- wallet/statements_gettextgen.po | 2 +- wallet/test/run-wallet.c | 6 +++--- 11 files changed, 77 insertions(+), 29 deletions(-) diff --git a/channeld/channeld.c b/channeld/channeld.c index c8479b0471d0..f385a72ce486 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -927,6 +927,7 @@ static u8 *sending_commitsig_msg(const tal_t *ctx, u64 remote_commit_index, struct penalty_base *pbase, const struct fee_states *fee_states, + const struct height_states *blockheight_states, const struct htlc **changed_htlcs, const struct bitcoin_signature *commit_sig, const struct bitcoin_signature *htlc_sigs) @@ -937,8 +938,10 @@ static u8 *sending_commitsig_msg(const tal_t *ctx, /* We tell master what (of our) HTLCs peer will now be * committed to. */ changed = changed_htlc_arr(tmpctx, changed_htlcs); - msg = towire_channeld_sending_commitsig(ctx, remote_commit_index, pbase, fee_states, changed, - commit_sig, htlc_sigs); + msg = towire_channeld_sending_commitsig(ctx, remote_commit_index, + pbase, fee_states, + blockheight_states, changed, + commit_sig, htlc_sigs); return msg; } @@ -1370,6 +1373,7 @@ static void send_commit(struct peer *peer) msg = sending_commitsig_msg(NULL, peer->next_index[REMOTE], pbase, peer->channel->fee_states, + peer->channel->blockheight_states, changed_htlcs, &commit_sig, htlc_sigs); @@ -1544,6 +1548,7 @@ static void send_revocation(struct peer *peer, = towire_channeld_got_commitsig(NULL, peer->next_index[LOCAL] - 1, peer->channel->fee_states, + peer->channel->blockheight_states, commit_sig, htlc_sigs, added, fulfilled, @@ -1722,7 +1727,8 @@ static u8 *got_revoke_msg(struct peer *peer, u64 revoke_num, const struct secret *per_commitment_secret, const struct pubkey *next_per_commit_point, const struct htlc **changed_htlcs, - const struct fee_states *fee_states) + const struct fee_states *fee_states, + const struct height_states *blockheight_states) { u8 *msg; struct penalty_base *pbase; @@ -1754,7 +1760,8 @@ static u8 *got_revoke_msg(struct peer *peer, u64 revoke_num, msg = towire_channeld_got_revoke(peer, revoke_num, per_commitment_secret, next_per_commit_point, fee_states, - changed, pbase, ptx); + blockheight_states, changed, + pbase, ptx); tal_free(ptx); return msg; } @@ -1811,7 +1818,8 @@ static void handle_peer_revoke_and_ack(struct peer *peer, const u8 *msg) msg = got_revoke_msg(peer, peer->revocations_received++, &old_commit_secret, &next_per_commit, changed_htlcs, - peer->channel->fee_states); + peer->channel->fee_states, + peer->channel->blockheight_states); master_wait_sync_reply(tmpctx, peer, take(msg), WIRE_CHANNELD_GOT_REVOKE_REPLY); diff --git a/channeld/channeld_wire.csv b/channeld/channeld_wire.csv index 07efef0fc210..2df499fe50e6 100644 --- a/channeld/channeld_wire.csv +++ b/channeld/channeld_wire.csv @@ -119,6 +119,7 @@ msgtype,channeld_sending_commitsig,1020 msgdata,channeld_sending_commitsig,commitnum,u64, msgdata,channeld_sending_commitsig,pbase,?penalty_base, msgdata,channeld_sending_commitsig,fee_states,fee_states, +msgdata,channeld_sending_commitsig,blockheight_states,height_states, # SENT_ADD_COMMIT, SENT_REMOVE_ACK_COMMIT, SENT_ADD_ACK_COMMIT, SENT_REMOVE_COMMIT msgdata,channeld_sending_commitsig,num_changed,u16, msgdata,channeld_sending_commitsig,changed,changed_htlc,num_changed @@ -133,6 +134,7 @@ msgtype,channeld_sending_commitsig_reply,1120 msgtype,channeld_got_commitsig,1021 msgdata,channeld_got_commitsig,commitnum,u64, msgdata,channeld_got_commitsig,fee_states,fee_states, +msgdata,channeld_got_commitsig,blockheight_states,height_states, msgdata,channeld_got_commitsig,signature,bitcoin_signature, msgdata,channeld_got_commitsig,num_htlcs,u16, msgdata,channeld_got_commitsig,htlc_signature,bitcoin_signature,num_htlcs @@ -160,6 +162,7 @@ msgdata,channeld_got_revoke,per_commitment_secret,secret, msgdata,channeld_got_revoke,next_per_commit_point,pubkey, # RCVD_ADD_ACK_REVOCATION, RCVD_REMOVE_ACK_REVOCATION, RCVD_ADD_REVOCATION, RCVD_REMOVE_REVOCATION msgdata,channeld_got_revoke,fee_states,fee_states, +msgdata,channeld_got_revoke,blockheight_states,height_states, msgdata,channeld_got_revoke,num_changed,u16, msgdata,channeld_got_revoke,changed,changed_htlc,num_changed msgdata,channeld_got_revoke,pbase,?penalty_base, diff --git a/channeld/channeld_wiregen.c b/channeld/channeld_wiregen.c index 06bb5f9a81ae..6e8a61adc8f3 100644 --- a/channeld/channeld_wiregen.c +++ b/channeld/channeld_wiregen.c @@ -482,7 +482,7 @@ bool fromwire_channeld_got_funding_locked(const void *p, struct pubkey *next_per /* WIRE: CHANNELD_SENDING_COMMITSIG */ /* When we send a commitment_signed message */ -u8 *towire_channeld_sending_commitsig(const tal_t *ctx, u64 commitnum, const struct penalty_base *pbase, const struct fee_states *fee_states, const struct changed_htlc *changed, const struct bitcoin_signature *commit_sig, const struct bitcoin_signature *htlc_sigs) +u8 *towire_channeld_sending_commitsig(const tal_t *ctx, u64 commitnum, const struct penalty_base *pbase, const struct fee_states *fee_states, const struct height_states *blockheight_states, const struct changed_htlc *changed, const struct bitcoin_signature *commit_sig, const struct bitcoin_signature *htlc_sigs) { u16 num_changed = tal_count(changed); u16 num_htlc_sigs = tal_count(htlc_sigs); @@ -497,6 +497,7 @@ u8 *towire_channeld_sending_commitsig(const tal_t *ctx, u64 commitnum, const str towire_penalty_base(&p, pbase); } towire_fee_states(&p, fee_states); + towire_height_states(&p, blockheight_states); /* SENT_ADD_COMMIT */ towire_u16(&p, num_changed); for (size_t i = 0; i < num_changed; i++) @@ -508,7 +509,7 @@ u8 *towire_channeld_sending_commitsig(const tal_t *ctx, u64 commitnum, const str return memcheck(p, tal_count(p)); } -bool fromwire_channeld_sending_commitsig(const tal_t *ctx, const void *p, u64 *commitnum, struct penalty_base **pbase, struct fee_states **fee_states, struct changed_htlc **changed, struct bitcoin_signature *commit_sig, struct bitcoin_signature **htlc_sigs) +bool fromwire_channeld_sending_commitsig(const tal_t *ctx, const void *p, u64 *commitnum, struct penalty_base **pbase, struct fee_states **fee_states, struct height_states **blockheight_states, struct changed_htlc **changed, struct bitcoin_signature *commit_sig, struct bitcoin_signature **htlc_sigs) { u16 num_changed; u16 num_htlc_sigs; @@ -526,6 +527,7 @@ bool fromwire_channeld_sending_commitsig(const tal_t *ctx, const void *p, u64 *c fromwire_penalty_base(&cursor, &plen, *pbase); } *fee_states = fromwire_fee_states(ctx, &cursor, &plen); + *blockheight_states = fromwire_height_states(ctx, &cursor, &plen); /* SENT_ADD_COMMIT */ num_changed = fromwire_u16(&cursor, &plen); // 2nd case changed @@ -563,7 +565,7 @@ bool fromwire_channeld_sending_commitsig_reply(const void *p) /* WIRE: CHANNELD_GOT_COMMITSIG */ /* When we have a commitment_signed message */ -u8 *towire_channeld_got_commitsig(const tal_t *ctx, u64 commitnum, const struct fee_states *fee_states, const struct bitcoin_signature *signature, const struct bitcoin_signature *htlc_signature, const struct added_htlc *added, const struct fulfilled_htlc *fulfilled, const struct failed_htlc **failed, const struct changed_htlc *changed, const struct bitcoin_tx *tx) +u8 *towire_channeld_got_commitsig(const tal_t *ctx, u64 commitnum, const struct fee_states *fee_states, const struct height_states *blockheight_states, const struct bitcoin_signature *signature, const struct bitcoin_signature *htlc_signature, const struct added_htlc *added, const struct fulfilled_htlc *fulfilled, const struct failed_htlc **failed, const struct changed_htlc *changed, const struct bitcoin_tx *tx) { u16 num_htlcs = tal_count(htlc_signature); u16 num_added = tal_count(added); @@ -575,6 +577,7 @@ u8 *towire_channeld_got_commitsig(const tal_t *ctx, u64 commitnum, const struct towire_u16(&p, WIRE_CHANNELD_GOT_COMMITSIG); towire_u64(&p, commitnum); towire_fee_states(&p, fee_states); + towire_height_states(&p, blockheight_states); towire_bitcoin_signature(&p, signature); towire_u16(&p, num_htlcs); for (size_t i = 0; i < num_htlcs; i++) @@ -598,7 +601,7 @@ u8 *towire_channeld_got_commitsig(const tal_t *ctx, u64 commitnum, const struct return memcheck(p, tal_count(p)); } -bool fromwire_channeld_got_commitsig(const tal_t *ctx, const void *p, u64 *commitnum, struct fee_states **fee_states, struct bitcoin_signature *signature, struct bitcoin_signature **htlc_signature, struct added_htlc **added, struct fulfilled_htlc **fulfilled, struct failed_htlc ***failed, struct changed_htlc **changed, struct bitcoin_tx **tx) +bool fromwire_channeld_got_commitsig(const tal_t *ctx, const void *p, u64 *commitnum, struct fee_states **fee_states, struct height_states **blockheight_states, struct bitcoin_signature *signature, struct bitcoin_signature **htlc_signature, struct added_htlc **added, struct fulfilled_htlc **fulfilled, struct failed_htlc ***failed, struct changed_htlc **changed, struct bitcoin_tx **tx) { u16 num_htlcs; u16 num_added; @@ -613,6 +616,7 @@ bool fromwire_channeld_got_commitsig(const tal_t *ctx, const void *p, u64 *commi return false; *commitnum = fromwire_u64(&cursor, &plen); *fee_states = fromwire_fee_states(ctx, &cursor, &plen); + *blockheight_states = fromwire_height_states(ctx, &cursor, &plen); fromwire_bitcoin_signature(&cursor, &plen, signature); num_htlcs = fromwire_u16(&cursor, &plen); // 2nd case htlc_signature @@ -667,7 +671,7 @@ bool fromwire_channeld_got_commitsig_reply(const void *p) } /* WIRE: CHANNELD_GOT_REVOKE */ -u8 *towire_channeld_got_revoke(const tal_t *ctx, u64 revokenum, const struct secret *per_commitment_secret, const struct pubkey *next_per_commit_point, const struct fee_states *fee_states, const struct changed_htlc *changed, const struct penalty_base *pbase, const struct bitcoin_tx *penalty_tx) +u8 *towire_channeld_got_revoke(const tal_t *ctx, u64 revokenum, const struct secret *per_commitment_secret, const struct pubkey *next_per_commit_point, const struct fee_states *fee_states, const struct height_states *blockheight_states, const struct changed_htlc *changed, const struct penalty_base *pbase, const struct bitcoin_tx *penalty_tx) { u16 num_changed = tal_count(changed); u8 *p = tal_arr(ctx, u8, 0); @@ -678,6 +682,7 @@ u8 *towire_channeld_got_revoke(const tal_t *ctx, u64 revokenum, const struct sec towire_pubkey(&p, next_per_commit_point); /* RCVD_ADD_ACK_REVOCATION */ towire_fee_states(&p, fee_states); + towire_height_states(&p, blockheight_states); towire_u16(&p, num_changed); for (size_t i = 0; i < num_changed; i++) towire_changed_htlc(&p, changed + i); @@ -696,7 +701,7 @@ u8 *towire_channeld_got_revoke(const tal_t *ctx, u64 revokenum, const struct sec return memcheck(p, tal_count(p)); } -bool fromwire_channeld_got_revoke(const tal_t *ctx, const void *p, u64 *revokenum, struct secret *per_commitment_secret, struct pubkey *next_per_commit_point, struct fee_states **fee_states, struct changed_htlc **changed, struct penalty_base **pbase, struct bitcoin_tx **penalty_tx) +bool fromwire_channeld_got_revoke(const tal_t *ctx, const void *p, u64 *revokenum, struct secret *per_commitment_secret, struct pubkey *next_per_commit_point, struct fee_states **fee_states, struct height_states **blockheight_states, struct changed_htlc **changed, struct penalty_base **pbase, struct bitcoin_tx **penalty_tx) { u16 num_changed; @@ -710,6 +715,7 @@ bool fromwire_channeld_got_revoke(const tal_t *ctx, const void *p, u64 *revokenu fromwire_pubkey(&cursor, &plen, next_per_commit_point); /* RCVD_ADD_ACK_REVOCATION */ *fee_states = fromwire_fee_states(ctx, &cursor, &plen); + *blockheight_states = fromwire_height_states(ctx, &cursor, &plen); num_changed = fromwire_u16(&cursor, &plen); // 2nd case changed *changed = num_changed ? tal_arr(ctx, struct changed_htlc, num_changed) : NULL; @@ -1167,4 +1173,4 @@ bool fromwire_channeld_blockheight(const void *p, u32 *blockheight) *blockheight = fromwire_u32(&cursor, &plen); return cursor != NULL; } -// SHA256STAMP:943ce198f20b823bbf667e253b66b1810caa3aac410e55744ac0cbeb7438904a +// SHA256STAMP:8abda9aa7ebc8598eba2e8827f4214d63f1188fefab17b28d77dce0198e3dfc6 diff --git a/channeld/channeld_wiregen.h b/channeld/channeld_wiregen.h index 3b4bb4b0b6e4..9edca74464b2 100644 --- a/channeld/channeld_wiregen.h +++ b/channeld/channeld_wiregen.h @@ -129,8 +129,8 @@ bool fromwire_channeld_got_funding_locked(const void *p, struct pubkey *next_per /* WIRE: CHANNELD_SENDING_COMMITSIG */ /* When we send a commitment_signed message */ -u8 *towire_channeld_sending_commitsig(const tal_t *ctx, u64 commitnum, const struct penalty_base *pbase, const struct fee_states *fee_states, const struct changed_htlc *changed, const struct bitcoin_signature *commit_sig, const struct bitcoin_signature *htlc_sigs); -bool fromwire_channeld_sending_commitsig(const tal_t *ctx, const void *p, u64 *commitnum, struct penalty_base **pbase, struct fee_states **fee_states, struct changed_htlc **changed, struct bitcoin_signature *commit_sig, struct bitcoin_signature **htlc_sigs); +u8 *towire_channeld_sending_commitsig(const tal_t *ctx, u64 commitnum, const struct penalty_base *pbase, const struct fee_states *fee_states, const struct height_states *blockheight_states, const struct changed_htlc *changed, const struct bitcoin_signature *commit_sig, const struct bitcoin_signature *htlc_sigs); +bool fromwire_channeld_sending_commitsig(const tal_t *ctx, const void *p, u64 *commitnum, struct penalty_base **pbase, struct fee_states **fee_states, struct height_states **blockheight_states, struct changed_htlc **changed, struct bitcoin_signature *commit_sig, struct bitcoin_signature **htlc_sigs); /* WIRE: CHANNELD_SENDING_COMMITSIG_REPLY */ /* Wait for reply */ @@ -139,8 +139,8 @@ bool fromwire_channeld_sending_commitsig_reply(const void *p); /* WIRE: CHANNELD_GOT_COMMITSIG */ /* When we have a commitment_signed message */ -u8 *towire_channeld_got_commitsig(const tal_t *ctx, u64 commitnum, const struct fee_states *fee_states, const struct bitcoin_signature *signature, const struct bitcoin_signature *htlc_signature, const struct added_htlc *added, const struct fulfilled_htlc *fulfilled, const struct failed_htlc **failed, const struct changed_htlc *changed, const struct bitcoin_tx *tx); -bool fromwire_channeld_got_commitsig(const tal_t *ctx, const void *p, u64 *commitnum, struct fee_states **fee_states, struct bitcoin_signature *signature, struct bitcoin_signature **htlc_signature, struct added_htlc **added, struct fulfilled_htlc **fulfilled, struct failed_htlc ***failed, struct changed_htlc **changed, struct bitcoin_tx **tx); +u8 *towire_channeld_got_commitsig(const tal_t *ctx, u64 commitnum, const struct fee_states *fee_states, const struct height_states *blockheight_states, const struct bitcoin_signature *signature, const struct bitcoin_signature *htlc_signature, const struct added_htlc *added, const struct fulfilled_htlc *fulfilled, const struct failed_htlc **failed, const struct changed_htlc *changed, const struct bitcoin_tx *tx); +bool fromwire_channeld_got_commitsig(const tal_t *ctx, const void *p, u64 *commitnum, struct fee_states **fee_states, struct height_states **blockheight_states, struct bitcoin_signature *signature, struct bitcoin_signature **htlc_signature, struct added_htlc **added, struct fulfilled_htlc **fulfilled, struct failed_htlc ***failed, struct changed_htlc **changed, struct bitcoin_tx **tx); /* WIRE: CHANNELD_GOT_COMMITSIG_REPLY */ /* Wait for reply */ @@ -148,8 +148,8 @@ u8 *towire_channeld_got_commitsig_reply(const tal_t *ctx); bool fromwire_channeld_got_commitsig_reply(const void *p); /* WIRE: CHANNELD_GOT_REVOKE */ -u8 *towire_channeld_got_revoke(const tal_t *ctx, u64 revokenum, const struct secret *per_commitment_secret, const struct pubkey *next_per_commit_point, const struct fee_states *fee_states, const struct changed_htlc *changed, const struct penalty_base *pbase, const struct bitcoin_tx *penalty_tx); -bool fromwire_channeld_got_revoke(const tal_t *ctx, const void *p, u64 *revokenum, struct secret *per_commitment_secret, struct pubkey *next_per_commit_point, struct fee_states **fee_states, struct changed_htlc **changed, struct penalty_base **pbase, struct bitcoin_tx **penalty_tx); +u8 *towire_channeld_got_revoke(const tal_t *ctx, u64 revokenum, const struct secret *per_commitment_secret, const struct pubkey *next_per_commit_point, const struct fee_states *fee_states, const struct height_states *blockheight_states, const struct changed_htlc *changed, const struct penalty_base *pbase, const struct bitcoin_tx *penalty_tx); +bool fromwire_channeld_got_revoke(const tal_t *ctx, const void *p, u64 *revokenum, struct secret *per_commitment_secret, struct pubkey *next_per_commit_point, struct fee_states **fee_states, struct height_states **blockheight_states, struct changed_htlc **changed, struct penalty_base **pbase, struct bitcoin_tx **penalty_tx); /* WIRE: CHANNELD_GOT_REVOKE_REPLY */ /* Wait for reply */ @@ -240,4 +240,4 @@ bool fromwire_channeld_blockheight(const void *p, u32 *blockheight); #endif /* LIGHTNING_CHANNELD_CHANNELD_WIREGEN_H */ -// SHA256STAMP:943ce198f20b823bbf667e253b66b1810caa3aac410e55744ac0cbeb7438904a +// SHA256STAMP:8abda9aa7ebc8598eba2e8827f4214d63f1188fefab17b28d77dce0198e3dfc6 diff --git a/common/initial_channel.c b/common/initial_channel.c index b5c02767b6f8..5cf9d2edc5c3 100644 --- a/common/initial_channel.c +++ b/common/initial_channel.c @@ -157,6 +157,12 @@ u32 channel_feerate(const struct channel *channel, enum side side) return get_feerate(channel->fee_states, channel->opener, side); } +u32 channel_blockheight(const struct channel *channel, enum side side) +{ + return get_blockheight(channel->blockheight_states, + channel->opener, side); +} + #if EXPERIMENTAL_FEATURES /* BOLT-upgrade_protocol #2: * Channel features are explicitly enumerated as `channel_type` bitfields, diff --git a/common/initial_channel.h b/common/initial_channel.h index 959c66ba4368..13dcb5e49f2c 100644 --- a/common/initial_channel.h +++ b/common/initial_channel.h @@ -151,6 +151,13 @@ struct bitcoin_tx *initial_channel_tx(const tal_t *ctx, */ u32 channel_feerate(const struct channel *channel, enum side side); +/** + * channel_blockheight: Get blockheight for this side of channel. + * @channel: The channel + * @side: the side + */ +u32 channel_blockheight(const struct channel *channel, enum side side); + #if EXPERIMENTAL_FEATURES /* BOLT-upgrade_protocol #2: * Channel features are explicitly enumerated as `channel_type` bitfields, diff --git a/lightningd/peer_htlcs.c b/lightningd/peer_htlcs.c index d0887d65074b..7f93870d1245 100644 --- a/lightningd/peer_htlcs.c +++ b/lightningd/peer_htlcs.c @@ -1730,6 +1730,7 @@ void peer_sending_commitsig(struct channel *channel, const u8 *msg) { u64 commitnum; struct fee_states *fee_states; + struct height_states *blockheight_states; struct changed_htlc *changed_htlcs; size_t i, maxid = 0, num_local_added = 0; struct bitcoin_signature commit_sig; @@ -1741,9 +1742,11 @@ void peer_sending_commitsig(struct channel *channel, const u8 *msg) &commitnum, &pbase, &fee_states, + &blockheight_states, &changed_htlcs, &commit_sig, &htlc_sigs) - || !fee_states_valid(fee_states, channel->opener)) { + || !fee_states_valid(fee_states, channel->opener) + || !height_states_valid(blockheight_states, channel->opener)) { channel_internal_error(channel, "bad channel_sending_commitsig %s", tal_hex(channel, msg)); return; @@ -1786,6 +1789,9 @@ void peer_sending_commitsig(struct channel *channel, const u8 *msg) channel->opener, REMOTE)); + tal_free(channel->blockheight_states); + channel->blockheight_states = tal_steal(channel, blockheight_states); + if (!peer_save_commitsig_sent(channel, commitnum)) return; @@ -1921,6 +1927,7 @@ void peer_got_commitsig(struct channel *channel, const u8 *msg) { u64 commitnum; struct fee_states *fee_states; + struct height_states *blockheight_states; struct bitcoin_signature commit_sig, *htlc_sigs; struct added_htlc *added; struct fulfilled_htlc *fulfilled; @@ -1933,6 +1940,7 @@ void peer_got_commitsig(struct channel *channel, const u8 *msg) if (!fromwire_channeld_got_commitsig(msg, msg, &commitnum, &fee_states, + &blockheight_states, &commit_sig, &htlc_sigs, &added, @@ -1940,7 +1948,8 @@ void peer_got_commitsig(struct channel *channel, const u8 *msg) &failed, &changed, &tx) - || !fee_states_valid(fee_states, channel->opener)) { + || !fee_states_valid(fee_states, channel->opener) + || !height_states_valid(blockheight_states, channel->opener)) { channel_internal_error(channel, "bad fromwire_channeld_got_commitsig %s", tal_hex(channel, msg)); @@ -1969,8 +1978,9 @@ void peer_got_commitsig(struct channel *channel, const u8 *msg) log_debug(channel->log, "got commitsig %"PRIu64 - ": feerate %u, %zu added, %zu fulfilled, %zu failed, %zu changed", + ": feerate %u, blockheight: %u, %zu added, %zu fulfilled, %zu failed, %zu changed", commitnum, get_feerate(fee_states, channel->opener, LOCAL), + get_blockheight(blockheight_states, channel->opener, LOCAL), tal_count(added), tal_count(fulfilled), tal_count(failed), tal_count(changed)); @@ -2005,6 +2015,8 @@ void peer_got_commitsig(struct channel *channel, const u8 *msg) get_feerate(fee_states, channel->opener, LOCAL)); + tal_free(channel->blockheight_states); + channel->blockheight_states = tal_steal(channel, blockheight_states); /* Since we're about to send revoke, bump state again. */ if (!peer_sending_revocation(channel, added, fulfilled, failed, changed)) @@ -2081,6 +2093,7 @@ void peer_got_revoke(struct channel *channel, const u8 *msg) size_t i; struct lightningd *ld = channel->peer->ld; struct fee_states *fee_states; + struct height_states *blockheight_states; struct penalty_base *pbase; struct commitment_revocation_payload *payload; struct bitcoin_tx *penalty_tx; @@ -2089,10 +2102,12 @@ void peer_got_revoke(struct channel *channel, const u8 *msg) &revokenum, &per_commitment_secret, &next_per_commitment_point, &fee_states, + &blockheight_states, &changed, &pbase, &penalty_tx) - || !fee_states_valid(fee_states, channel->opener)) { + || !fee_states_valid(fee_states, channel->opener) + || !height_states_valid(blockheight_states, channel->opener)) { channel_internal_error(channel, "bad fromwire_channeld_got_revoke %s", tal_hex(channel, msg)); return; @@ -2155,6 +2170,9 @@ void peer_got_revoke(struct channel *channel, const u8 *msg) tal_free(channel->fee_states); channel->fee_states = tal_steal(channel, fee_states); + tal_free(channel->blockheight_states); + channel->blockheight_states = tal_steal(channel, blockheight_states); + /* FIXME: Check per_commitment_secret -> per_commit_point */ update_per_commit_point(channel, &next_per_commitment_point); diff --git a/wallet/db_postgres_sqlgen.c b/wallet/db_postgres_sqlgen.c index 5f79ff32d488..434473f52b92 100644 --- a/wallet/db_postgres_sqlgen.c +++ b/wallet/db_postgres_sqlgen.c @@ -2014,4 +2014,4 @@ struct db_query db_postgres_queries[] = { #endif /* LIGHTNINGD_WALLET_GEN_DB_POSTGRES */ -// SHA256STAMP:4aa3c138e6c172aff0958062fbf1cdfd14194424349c533a46a0407b7131b7be +// SHA256STAMP:7ec26901d6eff90c74fbac8885e3403b52e5555a161bf21cedcec8b5d62457e4 diff --git a/wallet/db_sqlite3_sqlgen.c b/wallet/db_sqlite3_sqlgen.c index b0bca4a2b0e2..02058f3240fc 100644 --- a/wallet/db_sqlite3_sqlgen.c +++ b/wallet/db_sqlite3_sqlgen.c @@ -2014,4 +2014,4 @@ struct db_query db_sqlite3_queries[] = { #endif /* LIGHTNINGD_WALLET_GEN_DB_SQLITE3 */ -// SHA256STAMP:4aa3c138e6c172aff0958062fbf1cdfd14194424349c533a46a0407b7131b7be +// SHA256STAMP:7ec26901d6eff90c74fbac8885e3403b52e5555a161bf21cedcec8b5d62457e4 diff --git a/wallet/statements_gettextgen.po b/wallet/statements_gettextgen.po index 9b064071f8e4..11148525c378 100644 --- a/wallet/statements_gettextgen.po +++ b/wallet/statements_gettextgen.po @@ -1329,4 +1329,4 @@ msgstr "" #: wallet/test/run-wallet.c:1696 msgid "INSERT INTO channels (id) VALUES (1);" msgstr "" -# SHA256STAMP:b2158376af794319787cce0ea1066b6778edb5a1e04841e539a79bc69b59db46 +# SHA256STAMP:961e19c597842de7935718de7979b986804b3c99078d3c4792b7fb76d7405217 diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 0f3acfa7ce48..744649c57ccf 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -132,16 +132,16 @@ bool feature_offered(const u8 *features UNNEEDED, size_t f UNNEEDED) bool fromwire_channeld_dev_memleak_reply(const void *p UNNEEDED, bool *leak UNNEEDED) { fprintf(stderr, "fromwire_channeld_dev_memleak_reply called!\n"); abort(); } /* Generated stub for fromwire_channeld_got_commitsig */ -bool fromwire_channeld_got_commitsig(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u64 *commitnum UNNEEDED, struct fee_states **fee_states UNNEEDED, struct bitcoin_signature *signature UNNEEDED, struct bitcoin_signature **htlc_signature UNNEEDED, struct added_htlc **added UNNEEDED, struct fulfilled_htlc **fulfilled UNNEEDED, struct failed_htlc ***failed UNNEEDED, struct changed_htlc **changed UNNEEDED, struct bitcoin_tx **tx UNNEEDED) +bool fromwire_channeld_got_commitsig(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u64 *commitnum UNNEEDED, struct fee_states **fee_states UNNEEDED, struct height_states **blockheight_states UNNEEDED, struct bitcoin_signature *signature UNNEEDED, struct bitcoin_signature **htlc_signature UNNEEDED, struct added_htlc **added UNNEEDED, struct fulfilled_htlc **fulfilled UNNEEDED, struct failed_htlc ***failed UNNEEDED, struct changed_htlc **changed UNNEEDED, struct bitcoin_tx **tx UNNEEDED) { fprintf(stderr, "fromwire_channeld_got_commitsig called!\n"); abort(); } /* Generated stub for fromwire_channeld_got_revoke */ -bool fromwire_channeld_got_revoke(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u64 *revokenum UNNEEDED, struct secret *per_commitment_secret UNNEEDED, struct pubkey *next_per_commit_point UNNEEDED, struct fee_states **fee_states UNNEEDED, struct changed_htlc **changed UNNEEDED, struct penalty_base **pbase UNNEEDED, struct bitcoin_tx **penalty_tx UNNEEDED) +bool fromwire_channeld_got_revoke(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u64 *revokenum UNNEEDED, struct secret *per_commitment_secret UNNEEDED, struct pubkey *next_per_commit_point UNNEEDED, struct fee_states **fee_states UNNEEDED, struct height_states **blockheight_states UNNEEDED, struct changed_htlc **changed UNNEEDED, struct penalty_base **pbase UNNEEDED, struct bitcoin_tx **penalty_tx UNNEEDED) { fprintf(stderr, "fromwire_channeld_got_revoke called!\n"); abort(); } /* Generated stub for fromwire_channeld_offer_htlc_reply */ bool fromwire_channeld_offer_htlc_reply(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u64 *id UNNEEDED, u8 **failuremsg UNNEEDED, wirestring **failurestr UNNEEDED) { fprintf(stderr, "fromwire_channeld_offer_htlc_reply called!\n"); abort(); } /* Generated stub for fromwire_channeld_sending_commitsig */ -bool fromwire_channeld_sending_commitsig(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u64 *commitnum UNNEEDED, struct penalty_base **pbase UNNEEDED, struct fee_states **fee_states UNNEEDED, struct changed_htlc **changed UNNEEDED, struct bitcoin_signature *commit_sig UNNEEDED, struct bitcoin_signature **htlc_sigs UNNEEDED) +bool fromwire_channeld_sending_commitsig(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u64 *commitnum UNNEEDED, struct penalty_base **pbase UNNEEDED, struct fee_states **fee_states UNNEEDED, struct height_states **blockheight_states UNNEEDED, struct changed_htlc **changed UNNEEDED, struct bitcoin_signature *commit_sig UNNEEDED, struct bitcoin_signature **htlc_sigs UNNEEDED) { fprintf(stderr, "fromwire_channeld_sending_commitsig called!\n"); abort(); } /* Generated stub for fromwire_connectd_peer_connected */ bool fromwire_connectd_peer_connected(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct node_id *id UNNEEDED, struct wireaddr_internal *addr UNNEEDED, bool *incoming UNNEEDED, struct per_peer_state **pps UNNEEDED, u8 **features UNNEEDED) From 123f95f06ee081222631db7326998cbd5cb7c5b6 Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 22 Jun 2021 16:49:04 -0500 Subject: [PATCH 33/56] liquidity-ad: wire in csv updates to commitment txs --- channeld/commit_tx.c | 28 +++++++++++++++++++++++++--- channeld/commit_tx.h | 2 ++ channeld/full_channel.c | 6 ++++-- channeld/test/run-commit_tx.c | 11 +++++++++++ channeld/test/run-full_channel.c | 2 ++ 5 files changed, 44 insertions(+), 5 deletions(-) diff --git a/channeld/commit_tx.c b/channeld/commit_tx.c index 045f1a83369c..cdee2bd92092 100644 --- a/channeld/commit_tx.c +++ b/channeld/commit_tx.c @@ -90,6 +90,8 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx, const struct pubkey *remote_funding_key, enum side opener, u16 to_self_delay, + u32 lease_expiry, + u32 blockheight, const struct keyset *keyset, u32 feerate_per_kw, struct amount_sat dust_limit, @@ -234,9 +236,16 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx, * output](#to_local-output). */ if (amount_msat_greater_eq_sat(self_pay, dust_limit)) { + /* BOLT- #3: + * In a leased channel, the `to_local` output that + * pays the `accepter` node is modified so that its + * CSV is equal to the greater of the + * `to_self_delay` or the `lease_end` - `blockheight`. + */ u8 *wscript = to_self_wscript(tmpctx, to_self_delay, - 1, /* FIXME: csv_lock */ + lease_expiry > blockheight ? + lease_expiry - blockheight : 0, keyset); u8 *p2wsh = scriptpubkey_p2wsh(tx, wscript); struct amount_sat amount = amount_msat_to_sat_round_down(self_pay); @@ -278,9 +287,22 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx, * Otherwise, this output is a simple P2WPKH to `remotepubkey`. */ if (option_anchor_outputs) { - /* FIXME: use csv_lock */ + /* BOLT- #3: + * ##### Leased channel (`option_will_fund`) + * + * If a `lease` applies to the channel, the + * `to_remote` output of the `initiator` + * ensures the `leasor` funds are not + * spendable until the lease expires. + * + * OP_CHECKSIGVERIFY + * MAX(1, lease_end - blockheight) + * OP_CHECKSEQUENCEVERIFY + */ + u32 csv_lock = lease_expiry > blockheight ? + lease_expiry - blockheight : 1; scriptpubkey = scriptpubkey_p2wsh(tmpctx, - anchor_to_remote_redeem(tmpctx, &keyset->other_payment_key, 1)); + anchor_to_remote_redeem(tmpctx, &keyset->other_payment_key, csv_lock)); } else { scriptpubkey = scriptpubkey_p2wpkh(tmpctx, &keyset->other_payment_key); diff --git a/channeld/commit_tx.h b/channeld/commit_tx.h index 54ebcebd2b8b..31fe5ac6e4e3 100644 --- a/channeld/commit_tx.h +++ b/channeld/commit_tx.h @@ -58,6 +58,8 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx, const struct pubkey *remote_funding_key, enum side opener, u16 to_self_delay, + u32 lease_expiry, + u32 blockheight, const struct keyset *keyset, u32 feerate_per_kw, struct amount_sat dust_limit, diff --git a/channeld/full_channel.c b/channeld/full_channel.c index 684859a500db..f9291a8d7e09 100644 --- a/channeld/full_channel.c +++ b/channeld/full_channel.c @@ -341,8 +341,10 @@ struct bitcoin_tx **channel_txs(const tal_t *ctx, &channel->funding_pubkey[side], &channel->funding_pubkey[!side], channel->opener, - channel->config[!side].to_self_delay, &keyset, - channel_feerate(channel, side), + channel->config[!side].to_self_delay, + channel->lease_expiry, + channel_blockheight(channel, side), + &keyset, channel_feerate(channel, side), channel->config[side].dust_limit, channel->view[side].owed[side], channel->view[side].owed[!side], committed, htlcmap, direct_outputs, commitment_number ^ channel->commitment_number_obscurer, diff --git a/channeld/test/run-commit_tx.c b/channeld/test/run-commit_tx.c index 66590b49f336..2006d7194320 100644 --- a/channeld/test/run-commit_tx.c +++ b/channeld/test/run-commit_tx.c @@ -800,6 +800,7 @@ int main(int argc, const char *argv[]) &local_funding_pubkey, &remote_funding_pubkey, LOCAL, to_self_delay, + 0, 0, /* No lease */ &keyset, feerate_per_kw, dust_limit, @@ -815,6 +816,7 @@ int main(int argc, const char *argv[]) &local_funding_pubkey, &remote_funding_pubkey, REMOTE, to_self_delay, + 0, 0, /* No lease */ &keyset, feerate_per_kw, dust_limit, @@ -863,6 +865,7 @@ int main(int argc, const char *argv[]) &local_funding_pubkey, &remote_funding_pubkey, LOCAL, to_self_delay, + 0, 0, /* No lease */ &keyset, feerate_per_kw, dust_limit, @@ -878,6 +881,7 @@ int main(int argc, const char *argv[]) &local_funding_pubkey, &remote_funding_pubkey, REMOTE, to_self_delay, + 0, 0, /* No lease */ &keyset, feerate_per_kw, dust_limit, @@ -914,6 +918,7 @@ int main(int argc, const char *argv[]) &local_funding_pubkey, &remote_funding_pubkey, LOCAL, to_self_delay, + 0, 0, /* No lease */ &keyset, feerate_per_kw, dust_limit, @@ -930,6 +935,7 @@ int main(int argc, const char *argv[]) &local_funding_pubkey, &remote_funding_pubkey, REMOTE, to_self_delay, + 0, 0, /* No lease */ &keyset, feerate_per_kw, dust_limit, @@ -972,6 +978,7 @@ int main(int argc, const char *argv[]) &local_funding_pubkey, &remote_funding_pubkey, LOCAL, to_self_delay, + 0, 0, /* No lease */ &keyset, feerate_per_kw-1, dust_limit, @@ -1020,6 +1027,7 @@ int main(int argc, const char *argv[]) &local_funding_pubkey, &remote_funding_pubkey, LOCAL, to_self_delay, + 0, 0, /* No lease */ &keyset, feerate_per_kw, dust_limit, @@ -1094,6 +1102,7 @@ int main(int argc, const char *argv[]) &local_funding_pubkey, &remote_funding_pubkey, LOCAL, to_self_delay, + 0, 0, /* No lease */ &keyset, feerate_per_kw, dust_limit, @@ -1148,6 +1157,7 @@ int main(int argc, const char *argv[]) &local_funding_pubkey, &remote_funding_pubkey, LOCAL, to_self_delay, + 0, 0, /* No lease */ &keyset, feerate_per_kw, dust_limit, @@ -1163,6 +1173,7 @@ int main(int argc, const char *argv[]) &local_funding_pubkey, &remote_funding_pubkey, REMOTE, to_self_delay, + 0, 0, /* No lease */ &keyset, feerate_per_kw, dust_limit, diff --git a/channeld/test/run-full_channel.c b/channeld/test/run-full_channel.c index 5cb373c901bb..c2c4eb7ac58a 100644 --- a/channeld/test/run-full_channel.c +++ b/channeld/test/run-full_channel.c @@ -534,6 +534,7 @@ int main(int argc, const char *argv[]) &local_funding_pubkey, &remote_funding_pubkey, LOCAL, remote_config->to_self_delay, + 0, 0, /* No lease */ &keyset, feerate_per_kw[LOCAL], local_config->dust_limit, @@ -664,6 +665,7 @@ int main(int argc, const char *argv[]) &local_funding_pubkey, &remote_funding_pubkey, LOCAL, remote_config->to_self_delay, + 0, 0, /* No lease */ &keyset, feerate_per_kw[LOCAL], local_config->dust_limit, to_local, to_remote, htlcs, &htlc_map, NULL, 0x2bb038521914 ^ 42, From 6e4344ad2c5abd90d7cf1a6b49161d5119fd1435 Mon Sep 17 00:00:00 2001 From: niftynei Date: Wed, 23 Jun 2021 14:31:47 -0500 Subject: [PATCH 34/56] chaintopology: new command 'parsefeerate' Useful for parsing a passed in feerate before calling lightningd with it, e.g. when you need to know what the feerate is for a fundpsbt before calling fundpsbt Changelog-Added: JSON-RPC: new command `parsefeerate` which takes a feerate string and returns the calculated perkw/perkb --- doc/Makefile | 1 + doc/index.rst | 1 + doc/lightning-feerates.7 | 6 ++-- doc/lightning-feerates.7.md | 4 +-- doc/lightning-parsefeerate.7 | 44 +++++++++++++++++++++++++++ doc/lightning-parsefeerate.7.md | 45 ++++++++++++++++++++++++++++ doc/schemas/parsefeerate.schema.json | 13 ++++++++ lightningd/chaintopology.c | 27 +++++++++++++++++ tests/test_misc.py | 12 ++++++++ 9 files changed, 148 insertions(+), 5 deletions(-) create mode 100644 doc/lightning-parsefeerate.7 create mode 100644 doc/lightning-parsefeerate.7.md create mode 100644 doc/schemas/parsefeerate.schema.json diff --git a/doc/Makefile b/doc/Makefile index 30f4804d7168..17afdc3751bc 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -55,6 +55,7 @@ MANPAGES := doc/lightning-cli.1 \ doc/lightning-openchannel_signed.7 \ doc/lightning-openchannel_update.7 \ doc/lightning-pay.7 \ + doc/lightning-parsefeerate.7 \ doc/lightning-plugin.7 \ doc/lightning-reserveinputs.7 \ doc/lightning-sendinvoice.7 \ diff --git a/doc/index.rst b/doc/index.rst index d89b01aed7d7..d34db0943d3d 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -83,6 +83,7 @@ c-lightning Documentation lightning-openchannel_init lightning-openchannel_signed lightning-openchannel_update + lightning-parsefeerate lightning-pay lightning-ping lightning-plugin diff --git a/doc/lightning-feerates.7 b/doc/lightning-feerates.7 index 294aeaf2fc46..0ce3f10cc2df 100644 --- a/doc/lightning-feerates.7 +++ b/doc/lightning-feerates.7 @@ -162,11 +162,11 @@ manpage\. .SH SEE ALSO -\fBlightning-fundchannel\fR(7), \fBlightning-withdraw\fR(7), \fBlightning-txprepare\fR(7), -\fBlightning-fundchannel_start\fR(7)\. +\fBlightning-parsefeerate\fR(7), \fBlightning-fundchannel\fR(7), \fBlightning-withdraw\fR(7), +\fBlightning-txprepare\fR(7), \fBlightning-fundchannel_start\fR(7)\. .SH RESOURCES Main web site: \fIhttps://github.com/ElementsProject/lightning\fR -\" SHA256STAMP:6e1ae2f26676a76231461ac1f696066e538edabfab00ec9480550a5c6bc6981e +\" SHA256STAMP:bfa51e0f06e7616497c9be3a9f5737bc4378d8118db9e57a3f4efebd112f375a diff --git a/doc/lightning-feerates.7.md b/doc/lightning-feerates.7.md index 79ae753e669e..6f54c387da2e 100644 --- a/doc/lightning-feerates.7.md +++ b/doc/lightning-feerates.7.md @@ -110,8 +110,8 @@ manpage. SEE ALSO -------- -lightning-fundchannel(7), lightning-withdraw(7), lightning-txprepare(7), -lightning-fundchannel_start(7). +lightning-parsefeerate(7), lightning-fundchannel(7), lightning-withdraw(7), +lightning-txprepare(7), lightning-fundchannel_start(7). RESOURCES --------- diff --git a/doc/lightning-parsefeerate.7 b/doc/lightning-parsefeerate.7 new file mode 100644 index 000000000000..7c4a63b02ac3 --- /dev/null +++ b/doc/lightning-parsefeerate.7 @@ -0,0 +1,44 @@ +.TH "LIGHTNING-PARSEFEERATE" "7" "" "" "lightning-parsefeerate" +.SH NAME +lightning-parsefeerate - Command for parsing a feerate string to a feerate +.SH SYNOPSIS + +\fBparsefeerate\fR \fIfeerate_str\fR + +.SH DESCRIPTION + +The \fBparsefeerate\fR command returns the current feerate for any valid +\fIfeerate_str\fR\. This is useful for finding the current feerate that a +\fBfundpsbt\fR or \fButxopsbt\fR command might use\. + +.SH RETURN VALUE + +On success, an object is returned, containing: + +.RS +.IP \[bu] +\fBperkw\fR (u32, optional): Value of \fIfeerate_str\fR in kilosipa + +.RE +.SH ERRORS + +The \fBparsefeerate\fR command will error if the \fIfeerate_str\fR format is +not recognized\. + +.RS +.IP \[bu] +-32602: If the given parameters are wrong\. + +.RE +.SH TRIVIA + +In C-lightning we like to call the weight unit "sipa" +in honor of Pieter Wuille, +who uses the name "sipa" on IRC and elsewhere\. +Internally we call the \fIperkw\fR style as "feerate per kilosipa"\. + +.SH RESOURCES + +Main web site: \fIhttps://github.com/ElementsProject/lightning\fR + +\" SHA256STAMP:3b79a80f8129d715b3e78778deb85a1839af53efbca8ffb2e67511a8556722c0 diff --git a/doc/lightning-parsefeerate.7.md b/doc/lightning-parsefeerate.7.md new file mode 100644 index 000000000000..31a9da97de6d --- /dev/null +++ b/doc/lightning-parsefeerate.7.md @@ -0,0 +1,45 @@ +lightning-parsefeerate -- Command for parsing a feerate string to a feerate +=========================================================================== + +SYNOPSIS +-------- + +**parsefeerate** *feerate_str* + +DESCRIPTION +----------- + +The **parsefeerate** command returns the current feerate for any valid +*feerate_str*. This is useful for finding the current feerate that a +**fundpsbt** or **utxopsbt** command might use. + +RETURN VALUE +------------ + +[comment]: # (GENERATE-FROM-SCHEMA-START) +On success, an object is returned, containing: +- **perkw** (u32, optional): Value of *feerate_str* in kilosipa +[comment]: # (GENERATE-FROM-SCHEMA-END) + +ERRORS +------ + +The **parsefeerate** command will error if the *feerate_str* format is +not recognized. + +- -32602: If the given parameters are wrong. + +TRIVIA +------ + +In C-lightning we like to call the weight unit "sipa" +in honor of Pieter Wuille, +who uses the name "sipa" on IRC and elsewhere. +Internally we call the *perkw* style as "feerate per kilosipa". + +RESOURCES +--------- + +Main web site: + +[comment]: # ( SHA256STAMP:836154538ca2e2dd986255adc3e71e6047d4fa1d3d9ab9244e7248d10fef0d26) diff --git a/doc/schemas/parsefeerate.schema.json b/doc/schemas/parsefeerate.schema.json new file mode 100644 index 000000000000..0af834cfe3fd --- /dev/null +++ b/doc/schemas/parsefeerate.schema.json @@ -0,0 +1,13 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "additionalProperties": false, + "required": [ ], + "properties": { + "perkw": { + "type": "u32", + "description": "Value of *feerate_str* in kilosipa", + "additionalProperties": false + } + } +} diff --git a/lightningd/chaintopology.c b/lightningd/chaintopology.c index 949e0f0f615f..6f624c839dd3 100644 --- a/lightningd/chaintopology.c +++ b/lightningd/chaintopology.c @@ -553,6 +553,33 @@ static const struct json_command feerates_command = { }; AUTODATA(json_command, &feerates_command); +static struct command_result *json_parse_feerate(struct command *cmd, + const char *buffer, + const jsmntok_t *obj UNNEEDED, + const jsmntok_t *params) +{ + struct json_stream *response; + u32 *feerate; + + if (!param(cmd, buffer, params, + p_req("feerate", param_feerate, &feerate), + NULL)) + return command_param_failed(); + + response = json_stream_success(cmd); + json_add_num(response, feerate_style_name(FEERATE_PER_KSIPA), + feerate_to_style(*feerate, FEERATE_PER_KSIPA)); + return command_success(cmd, response); +} + +static const struct json_command parse_feerate_command = { + "parsefeerate", + "bitcoin", + json_parse_feerate, + "Return current feerate in perkw + perkb for given feerate string." +}; +AUTODATA(json_command, &parse_feerate_command); + static void next_updatefee_timer(struct chain_topology *topo) { /* This takes care of its own lifetime. */ diff --git a/tests/test_misc.py b/tests/test_misc.py index c1dee2b55546..9bb5e7abb726 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -1460,6 +1460,11 @@ def test_feerates(node_factory): types = ["opening", "mutual_close", "unilateral_close", "delayed_to_us", "htlc_resolution", "penalty"] + # Try parsing the feerates, won't work because can't estimate + for t in types: + with pytest.raises(RpcError, match=r'Cannot estimate fees'): + feerate = l1.rpc.parsefeerate(t) + # Query feerates (shouldn't give any!) wait_for(lambda: len(l1.rpc.feerates('perkw')['perkw']) == 2) feerates = l1.rpc.feerates('perkw') @@ -1537,6 +1542,13 @@ def test_feerates(node_factory): htlc_feerate = feerates["perkw"]["htlc_resolution"] htlc_timeout_cost = feerates["onchain_fee_estimates"]["htlc_timeout_satoshis"] htlc_success_cost = feerates["onchain_fee_estimates"]["htlc_success_satoshis"] + + # Try parsing the feerates, won't work because can't estimate + for t in types: + feerate = l1.rpc.parsefeerate(t) + assert feerate['perkw'] + assert 'perkb' not in feerate + if EXPERIMENTAL_FEATURES: # option_anchor_outputs assert htlc_timeout_cost == htlc_feerate * 666 // 1000 From 64d7f44c9f3a4b6a2f54ca9def26e59d8a5fe379 Mon Sep 17 00:00:00 2001 From: niftynei Date: Wed, 23 Jun 2021 15:04:34 -0500 Subject: [PATCH 35/56] libplugin: add synchronous rpc call handler that returns an error Makes it a bit more flexible. --- plugins/libplugin.c | 58 +++++++++++++++++++++++++++++++++++---------- plugins/libplugin.h | 10 ++++++++ 2 files changed, 56 insertions(+), 12 deletions(-) diff --git a/plugins/libplugin.c b/plugins/libplugin.c index e824917241cd..b5a87d6e7e5a 100644 --- a/plugins/libplugin.c +++ b/plugins/libplugin.c @@ -484,11 +484,12 @@ static struct json_out *start_json_request(const tal_t *ctx, } /* Synchronous routine to send command and extract fields from response */ -void rpc_scan(struct plugin *plugin, - const char *method, - const struct json_out *params TAKES, - const char *guide, - ...) +static const char *rpc_scan_list(const tal_t *ctx, + struct plugin *plugin, + const char *method, + const struct json_out *params TAKES, + const char *guide, + va_list *ap) { bool error; const char *err; @@ -496,26 +497,59 @@ void rpc_scan(struct plugin *plugin, int reqlen; const char *p; struct json_out *jout; - va_list ap; jout = start_json_request(tmpctx, 0, method, params); finish_and_send_json(plugin->rpc_conn->fd, jout); read_rpc_reply(tmpctx, plugin, &contents, &error, &reqlen); if (error) - plugin_err(plugin, "Got error reply to %s: '%.*s'", - method, reqlen, membuf_elems(&plugin->rpc_conn->mb)); + return tal_fmt(ctx,"Got error reply to %s: '%.*s'", + method, reqlen, + membuf_elems(&plugin->rpc_conn->mb)); p = membuf_consume(&plugin->rpc_conn->mb, reqlen); + err = json_scanv(tmpctx, p, contents, guide, *ap); + if (err) + return tal_fmt(ctx, + "Could not parse %s in reply to %s: %s: '%.*s'", + guide, method, err, reqlen, + membuf_elems(&plugin->rpc_conn->mb)); + return NULL; +} + +const char *rpc_scan_err(const tal_t *ctx, + struct plugin *plugin, + const char *method, + const struct json_out *params TAKES, + const char *guide, + ...) +{ + va_list ap; + const char *err; + + va_start(ap, guide); + err = rpc_scan_list(ctx, plugin, method, params, guide, &ap); + va_end(ap); + + return err; +} + +void rpc_scan(struct plugin *plugin, + const char *method, + const struct json_out *params TAKES, + const char *guide, + ...) +{ + va_list ap; + const char *err; + va_start(ap, guide); - err = json_scanv(tmpctx, p, contents, guide, ap); + err = rpc_scan_list(plugin, plugin, method, params, guide, &ap); va_end(ap); if (err) - plugin_err(plugin, "Could not parse %s in reply to %s: %s: '%.*s'", - guide, method, err, - reqlen, membuf_elems(&plugin->rpc_conn->mb)); + plugin_err(plugin, err); } static void handle_rpc_reply(struct plugin *plugin, const jsmntok_t *toks) diff --git a/plugins/libplugin.h b/plugins/libplugin.h index e480ed50da32..d4dd02790518 100644 --- a/plugins/libplugin.h +++ b/plugins/libplugin.h @@ -193,6 +193,16 @@ void rpc_scan(struct plugin *plugin, const char *guide, ...); +/* Synchronous helper to send command and extract fields from + * response. Returns an error message if fails. + **/ +const char *rpc_scan_err(const tal_t *ctx, + struct plugin *plugin, + const char *method, + const struct json_out *params TAKES, + const char *guide, + ...); + /* Send an async rpc request to lightningd. */ struct command_result *send_outreq(struct plugin *plugin, const struct out_req *req); From 7887ad986815acdfd9ff5735b203b91a4e056855 Mon Sep 17 00:00:00 2001 From: niftynei Date: Fri, 2 Jul 2021 14:46:20 -0500 Subject: [PATCH 36/56] channel lease: set csv_lock for commitment transactions If the channel is under lease, the lessor's (accepter, really) funds have a CSV lock that reflects the length of the remainder of the lease. --- channeld/commit_tx.c | 17 +++++++++++------ common/initial_commit_tx.c | 11 ++++++++--- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/channeld/commit_tx.c b/channeld/commit_tx.c index cdee2bd92092..8718d7577e18 100644 --- a/channeld/commit_tx.c +++ b/channeld/commit_tx.c @@ -108,6 +108,8 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx, struct amount_msat total_pay; struct bitcoin_tx *tx; size_t i, n, untrimmed; + /* Is this the lessor ? */ + enum side lessor = !opener; u32 *cltvs; bool to_local, to_remote; struct htlc *dummy_to_local = (struct htlc *)0x01, @@ -115,6 +117,8 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx, const u8 *funding_wscript = bitcoin_redeem_2of2(tmpctx, local_funding_key, remote_funding_key); + u32 csv_lock = lease_expiry > blockheight ? + lease_expiry - blockheight : 1; if (!amount_msat_add(&total_pay, self_pay, other_pay)) abort(); @@ -244,8 +248,7 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx, */ u8 *wscript = to_self_wscript(tmpctx, to_self_delay, - lease_expiry > blockheight ? - lease_expiry - blockheight : 0, + side == lessor ? csv_lock : 0, keyset); u8 *p2wsh = scriptpubkey_p2wsh(tx, wscript); struct amount_sat amount = amount_msat_to_sat_round_down(self_pay); @@ -287,6 +290,11 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx, * Otherwise, this output is a simple P2WPKH to `remotepubkey`. */ if (option_anchor_outputs) { + const u8 *redeem + = anchor_to_remote_redeem(tmpctx, + &keyset->other_payment_key, + (!side) == lessor ? + csv_lock : 1); /* BOLT- #3: * ##### Leased channel (`option_will_fund`) * @@ -299,10 +307,7 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx, * MAX(1, lease_end - blockheight) * OP_CHECKSEQUENCEVERIFY */ - u32 csv_lock = lease_expiry > blockheight ? - lease_expiry - blockheight : 1; - scriptpubkey = scriptpubkey_p2wsh(tmpctx, - anchor_to_remote_redeem(tmpctx, &keyset->other_payment_key, csv_lock)); + scriptpubkey = scriptpubkey_p2wsh(tmpctx, redeem); } else { scriptpubkey = scriptpubkey_p2wpkh(tmpctx, &keyset->other_payment_key); diff --git a/common/initial_commit_tx.c b/common/initial_commit_tx.c index 593eaa5cc370..0330a7801cf0 100644 --- a/common/initial_commit_tx.c +++ b/common/initial_commit_tx.c @@ -98,6 +98,7 @@ struct bitcoin_tx *initial_commit_tx(const tal_t *ctx, bool to_local, to_remote; struct amount_msat total_pay; struct amount_sat amount; + enum side lessor = !opener; u32 sequence; void *dummy_local = (void *)LOCAL, *dummy_remote = (void *)REMOTE; const void *output_order[NUM_SIDES]; @@ -211,7 +212,8 @@ struct bitcoin_tx *initial_commit_tx(const tal_t *ctx, */ if (amount_msat_greater_eq_sat(self_pay, dust_limit)) { u8 *wscript = to_self_wscript(tmpctx, - to_self_delay, csv_lock, + to_self_delay, + side == lessor ? csv_lock : 0, keyset); amount = amount_msat_to_sat_round_down(self_pay); int pos = bitcoin_tx_add_output( @@ -245,8 +247,11 @@ struct bitcoin_tx *initial_commit_tx(const tal_t *ctx, amount = amount_msat_to_sat_round_down(other_pay); if (option_anchor_outputs) { - scriptpubkey = scriptpubkey_p2wsh(tmpctx, - anchor_to_remote_redeem(tmpctx, &keyset->other_payment_key, csv_lock)); + const u8 *redeem + = anchor_to_remote_redeem(tmpctx, + &keyset->other_payment_key, + (!side) == lessor ? csv_lock : 1); + scriptpubkey = scriptpubkey_p2wsh(tmpctx, redeem); } else { scriptpubkey = scriptpubkey_p2wpkh(tmpctx, &keyset->other_payment_key); From 7a7df1bf3b38495caf59790a47f086c68a8fd5ed Mon Sep 17 00:00:00 2001 From: niftynei Date: Fri, 2 Jul 2021 14:54:40 -0500 Subject: [PATCH 37/56] channel utxo: persist the 'csv' lock value to database Channel leases modify the CSV height that an output is eligible for being spent at, persist this to the database --- lightningd/onchain_control.c | 12 +- onchaind/onchaind.c | 3 +- onchaind/onchaind_wire.csv | 1 + onchaind/onchaind_wiregen.c | 8 +- onchaind/onchaind_wiregen.h | 6 +- onchaind/test/run-grind_feerate-bug.c | 2 +- onchaind/test/run-grind_feerate.c | 2 +- wallet/db.c | 1 + wallet/db_postgres_sqlgen.c | 36 ++- wallet/db_sqlite3_sqlgen.c | 36 ++- wallet/reservation.c | 2 +- wallet/statements_gettextgen.po | 310 +++++++++++++------------- wallet/wallet.c | 14 +- wallet/wallet.h | 4 +- wallet/walletrpc.c | 8 + 15 files changed, 254 insertions(+), 191 deletions(-) diff --git a/lightningd/onchain_control.c b/lightningd/onchain_control.c index 759ae4180333..33faacbd2bc3 100644 --- a/lightningd/onchain_control.c +++ b/lightningd/onchain_control.c @@ -382,14 +382,15 @@ static void onchain_add_utxo(struct channel *channel, const u8 *msg) struct chain_coin_mvt *mvt; u32 blockheight; struct bitcoin_txid txid; - u32 outnum; + u32 outnum, csv_lock; struct amount_sat amount; struct pubkey *commitment_point; u8 *scriptPubkey; if (!fromwire_onchaind_add_utxo( tmpctx, msg, &txid, &outnum, &commitment_point, - &amount, &blockheight, &scriptPubkey)) { + &amount, &blockheight, &scriptPubkey, + &csv_lock)) { log_broken(channel->log, "onchaind gave invalid add_utxo message: %s", tal_hex(msg, msg)); @@ -399,10 +400,15 @@ static void onchain_add_utxo(struct channel *channel, const u8 *msg) assert(blockheight); outpointfilter_add(channel->peer->ld->wallet->owned_outpoints, &txid, outnum); + log_debug(channel->log, "adding utxo to watch %s:%u, csv %u", + type_to_string(tmpctx, struct bitcoin_txid, &txid), + outnum, csv_lock); + wallet_add_onchaind_utxo(channel->peer->ld->wallet, &txid, outnum, scriptPubkey, blockheight, amount, channel, - commitment_point); + commitment_point, + csv_lock); mvt = new_coin_deposit_sat(msg, "wallet", &txid, outnum, blockheight, amount); diff --git a/onchaind/onchaind.c b/onchaind/onchaind.c index bc32a0b8d3e0..6baacd2b1e89 100644 --- a/onchaind/onchaind.c +++ b/onchaind/onchaind.c @@ -3031,7 +3031,8 @@ static void tell_wallet_to_remote(const struct tx_parts *tx, per_commit_point, amt, tx_blockheight, - scriptpubkey))); + scriptpubkey, + csv_lock))); } /* When a 'cheat' transaction comes through, our accounting is diff --git a/onchaind/onchaind_wire.csv b/onchaind/onchaind_wire.csv index 926ffb3924de..694ac7498dd4 100644 --- a/onchaind/onchaind_wire.csv +++ b/onchaind/onchaind_wire.csv @@ -119,6 +119,7 @@ msgdata,onchaind_add_utxo,value,amount_sat, msgdata,onchaind_add_utxo,blockheight,u32, msgdata,onchaind_add_utxo,len,u16, msgdata,onchaind_add_utxo,scriptpubkey,u8,len +msgdata,onchaind_add_utxo,csv_lock,u32, # master -> onchaind: do you have a memleak? msgtype,onchaind_dev_memleak,5033 diff --git a/onchaind/onchaind_wiregen.c b/onchaind/onchaind_wiregen.c index 6a32dabaec5f..b2daec9a26c3 100644 --- a/onchaind/onchaind_wiregen.c +++ b/onchaind/onchaind_wiregen.c @@ -476,7 +476,7 @@ bool fromwire_onchaind_all_irrevocably_resolved(const void *p) /* WIRE: ONCHAIND_ADD_UTXO */ /* onchaind->master: hey */ -u8 *towire_onchaind_add_utxo(const tal_t *ctx, const struct bitcoin_txid *prev_out_tx, u32 prev_out_index, const struct pubkey *per_commit_point, struct amount_sat value, u32 blockheight, const u8 *scriptpubkey) +u8 *towire_onchaind_add_utxo(const tal_t *ctx, const struct bitcoin_txid *prev_out_tx, u32 prev_out_index, const struct pubkey *per_commit_point, struct amount_sat value, u32 blockheight, const u8 *scriptpubkey, u32 csv_lock) { u16 len = tal_count(scriptpubkey); u8 *p = tal_arr(ctx, u8, 0); @@ -494,10 +494,11 @@ u8 *towire_onchaind_add_utxo(const tal_t *ctx, const struct bitcoin_txid *prev_o towire_u32(&p, blockheight); towire_u16(&p, len); towire_u8_array(&p, scriptpubkey, len); + towire_u32(&p, csv_lock); return memcheck(p, tal_count(p)); } -bool fromwire_onchaind_add_utxo(const tal_t *ctx, const void *p, struct bitcoin_txid *prev_out_tx, u32 *prev_out_index, struct pubkey **per_commit_point, struct amount_sat *value, u32 *blockheight, u8 **scriptpubkey) +bool fromwire_onchaind_add_utxo(const tal_t *ctx, const void *p, struct bitcoin_txid *prev_out_tx, u32 *prev_out_index, struct pubkey **per_commit_point, struct amount_sat *value, u32 *blockheight, u8 **scriptpubkey, u32 *csv_lock) { u16 len; @@ -520,6 +521,7 @@ bool fromwire_onchaind_add_utxo(const tal_t *ctx, const void *p, struct bitcoin_ // 2nd case scriptpubkey *scriptpubkey = len ? tal_arr(ctx, u8, len) : NULL; fromwire_u8_array(&cursor, &plen, *scriptpubkey, len); + *csv_lock = fromwire_u32(&cursor, &plen); return cursor != NULL; } @@ -637,4 +639,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:08b8cb168df5294bb10d79d57cbefaa80072efcda5bf13b7f3469506623205bb +// SHA256STAMP:a1bc391f00c9cabd0194111f21966b39dcd1ab43819c0e126f0f390783e64980 diff --git a/onchaind/onchaind_wiregen.h b/onchaind/onchaind_wiregen.h index 57e38a93f03c..e1ea9fc709d9 100644 --- a/onchaind/onchaind_wiregen.h +++ b/onchaind/onchaind_wiregen.h @@ -132,8 +132,8 @@ bool fromwire_onchaind_all_irrevocably_resolved(const void *p); /* WIRE: ONCHAIND_ADD_UTXO */ /* onchaind->master: hey */ -u8 *towire_onchaind_add_utxo(const tal_t *ctx, const struct bitcoin_txid *prev_out_tx, u32 prev_out_index, const struct pubkey *per_commit_point, struct amount_sat value, u32 blockheight, const u8 *scriptpubkey); -bool fromwire_onchaind_add_utxo(const tal_t *ctx, const void *p, struct bitcoin_txid *prev_out_tx, u32 *prev_out_index, struct pubkey **per_commit_point, struct amount_sat *value, u32 *blockheight, u8 **scriptpubkey); +u8 *towire_onchaind_add_utxo(const tal_t *ctx, const struct bitcoin_txid *prev_out_tx, u32 prev_out_index, const struct pubkey *per_commit_point, struct amount_sat value, u32 blockheight, const u8 *scriptpubkey, u32 csv_lock); +bool fromwire_onchaind_add_utxo(const tal_t *ctx, const void *p, struct bitcoin_txid *prev_out_tx, u32 *prev_out_index, struct pubkey **per_commit_point, struct amount_sat *value, u32 *blockheight, u8 **scriptpubkey, u32 *csv_lock); /* WIRE: ONCHAIND_DEV_MEMLEAK */ /* master -> onchaind: do you have a memleak? */ @@ -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:08b8cb168df5294bb10d79d57cbefaa80072efcda5bf13b7f3469506623205bb +// SHA256STAMP:a1bc391f00c9cabd0194111f21966b39dcd1ab43819c0e126f0f390783e64980 diff --git a/onchaind/test/run-grind_feerate-bug.c b/onchaind/test/run-grind_feerate-bug.c index 8c44c52eded5..15dbcb75d746 100644 --- a/onchaind/test/run-grind_feerate-bug.c +++ b/onchaind/test/run-grind_feerate-bug.c @@ -235,7 +235,7 @@ u8 *towire_hsmd_sign_penalty_to_us(const tal_t *ctx UNNEEDED, const struct secre u8 *towire_hsmd_sign_remote_htlc_to_us(const tal_t *ctx UNNEEDED, const struct pubkey *remote_per_commitment_point UNNEEDED, const struct bitcoin_tx *tx UNNEEDED, const u8 *wscript UNNEEDED, bool option_anchor_outputs UNNEEDED) { fprintf(stderr, "towire_hsmd_sign_remote_htlc_to_us called!\n"); abort(); } /* Generated stub for towire_onchaind_add_utxo */ -u8 *towire_onchaind_add_utxo(const tal_t *ctx UNNEEDED, const struct bitcoin_txid *prev_out_tx UNNEEDED, u32 prev_out_index UNNEEDED, const struct pubkey *per_commit_point UNNEEDED, struct amount_sat value UNNEEDED, u32 blockheight UNNEEDED, const u8 *scriptpubkey UNNEEDED) +u8 *towire_onchaind_add_utxo(const tal_t *ctx UNNEEDED, const struct bitcoin_txid *prev_out_tx UNNEEDED, u32 prev_out_index UNNEEDED, const struct pubkey *per_commit_point UNNEEDED, struct amount_sat value UNNEEDED, u32 blockheight UNNEEDED, const u8 *scriptpubkey UNNEEDED, u32 csv_lock UNNEEDED) { fprintf(stderr, "towire_onchaind_add_utxo called!\n"); abort(); } /* Generated stub for towire_onchaind_all_irrevocably_resolved */ u8 *towire_onchaind_all_irrevocably_resolved(const tal_t *ctx UNNEEDED) diff --git a/onchaind/test/run-grind_feerate.c b/onchaind/test/run-grind_feerate.c index c89ecef9ed0d..61bdbeda771d 100644 --- a/onchaind/test/run-grind_feerate.c +++ b/onchaind/test/run-grind_feerate.c @@ -255,7 +255,7 @@ u8 *towire_hsmd_sign_penalty_to_us(const tal_t *ctx UNNEEDED, const struct secre u8 *towire_hsmd_sign_remote_htlc_to_us(const tal_t *ctx UNNEEDED, const struct pubkey *remote_per_commitment_point UNNEEDED, const struct bitcoin_tx *tx UNNEEDED, const u8 *wscript UNNEEDED, bool option_anchor_outputs UNNEEDED) { fprintf(stderr, "towire_hsmd_sign_remote_htlc_to_us called!\n"); abort(); } /* Generated stub for towire_onchaind_add_utxo */ -u8 *towire_onchaind_add_utxo(const tal_t *ctx UNNEEDED, const struct bitcoin_txid *prev_out_tx UNNEEDED, u32 prev_out_index UNNEEDED, const struct pubkey *per_commit_point UNNEEDED, struct amount_sat value UNNEEDED, u32 blockheight UNNEEDED, const u8 *scriptpubkey UNNEEDED) +u8 *towire_onchaind_add_utxo(const tal_t *ctx UNNEEDED, const struct bitcoin_txid *prev_out_tx UNNEEDED, u32 prev_out_index UNNEEDED, const struct pubkey *per_commit_point UNNEEDED, struct amount_sat value UNNEEDED, u32 blockheight UNNEEDED, const u8 *scriptpubkey UNNEEDED, u32 csv_lock UNNEEDED) { fprintf(stderr, "towire_onchaind_add_utxo called!\n"); abort(); } /* Generated stub for towire_onchaind_all_irrevocably_resolved */ u8 *towire_onchaind_all_irrevocably_resolved(const tal_t *ctx UNNEEDED) diff --git a/wallet/db.c b/wallet/db.c index 472f12923e68..a56aa37790ef 100644 --- a/wallet/db.c +++ b/wallet/db.c @@ -748,6 +748,7 @@ static struct migration dbmigrations[] = { " UNIQUE (channel_id, hstate)" ");"), fillin_missing_channel_blockheights}, + {SQL("ALTER TABLE outputs ADD csv_lock INTEGER DEFAULT 1;"), NULL}, }; /* Leak tracking. */ diff --git a/wallet/db_postgres_sqlgen.c b/wallet/db_postgres_sqlgen.c index 434473f52b92..f532c90e77ff 100644 --- a/wallet/db_postgres_sqlgen.c +++ b/wallet/db_postgres_sqlgen.c @@ -1016,6 +1016,12 @@ struct db_query db_postgres_queries[] = { .placeholders = 0, .readonly = false, }, + { + .name = "ALTER TABLE outputs ADD csv_lock INTEGER DEFAULT 1;", + .query = "ALTER TABLE outputs ADD csv_lock INTEGER DEFAULT 1;", + .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", @@ -1269,26 +1275,26 @@ struct db_query db_postgres_queries[] = { .readonly = false, }, { - .name = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til FROM outputs", - .query = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til FROM outputs", + .name = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til , csv_lock FROM outputs", + .query = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til , csv_lock FROM outputs", .placeholders = 0, .readonly = true, }, { - .name = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til FROM outputs WHERE status= ? ", - .query = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til FROM outputs WHERE status= $1 ", + .name = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til , csv_lock FROM outputs WHERE status= ? ", + .query = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til , csv_lock FROM outputs WHERE status= $1 ", .placeholders = 1, .readonly = true, }, { - .name = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey, reserved_til FROM outputs WHERE channel_id IS NOT NULL AND confirmation_height IS NULL", - .query = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey, reserved_til FROM outputs WHERE channel_id IS NOT NULL AND confirmation_height IS NULL", + .name = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey, reserved_til, csv_lock FROM outputs WHERE channel_id IS NOT NULL AND confirmation_height IS NULL", + .query = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey, reserved_til, csv_lock FROM outputs WHERE channel_id IS NOT NULL AND confirmation_height IS NULL", .placeholders = 0, .readonly = true, }, { - .name = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey, reserved_til FROM outputs WHERE prev_out_tx = ? AND prev_out_index = ?", - .query = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey, reserved_til FROM outputs WHERE prev_out_tx = $1 AND prev_out_index = $2", + .name = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey, reserved_til, csv_lock FROM outputs WHERE prev_out_tx = ? AND prev_out_index = ?", + .query = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey, reserved_til, csv_lock FROM outputs WHERE prev_out_tx = $1 AND prev_out_index = $2", .placeholders = 2, .readonly = true, }, @@ -1299,11 +1305,17 @@ struct db_query db_postgres_queries[] = { .readonly = false, }, { - .name = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til FROM outputs WHERE status = ? OR (status = ? AND reserved_til <= ?)ORDER BY RANDOM();", - .query = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til FROM outputs WHERE status = $1 OR (status = $2 AND reserved_til <= $3)ORDER BY RANDOM();", + .name = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til, csv_lock FROM outputs WHERE status = ? OR (status = ? AND reserved_til <= ?)ORDER BY RANDOM();", + .query = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til, csv_lock FROM outputs WHERE status = $1 OR (status = $2 AND reserved_til <= $3)ORDER BY RANDOM();", .placeholders = 3, .readonly = true, }, + { + .name = "INSERT INTO outputs ( prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey, csv_lock) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", + .query = "INSERT INTO outputs ( prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey, csv_lock) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14);", + .placeholders = 14, + .readonly = false, + }, { .name = "INSERT INTO shachains (min_index, num_valid) VALUES (?, 0);", .query = "INSERT INTO shachains (min_index, num_valid) VALUES ($1, 0);", @@ -2008,10 +2020,10 @@ struct db_query db_postgres_queries[] = { }, }; -#define DB_POSTGRES_QUERY_COUNT 333 +#define DB_POSTGRES_QUERY_COUNT 335 #endif /* HAVE_POSTGRES */ #endif /* LIGHTNINGD_WALLET_GEN_DB_POSTGRES */ -// SHA256STAMP:7ec26901d6eff90c74fbac8885e3403b52e5555a161bf21cedcec8b5d62457e4 +// SHA256STAMP:7969d7dbe623730766408455852a9ca4394f05129258c8ebe7ffbdc47c5359b1 diff --git a/wallet/db_sqlite3_sqlgen.c b/wallet/db_sqlite3_sqlgen.c index 02058f3240fc..7e44b6638720 100644 --- a/wallet/db_sqlite3_sqlgen.c +++ b/wallet/db_sqlite3_sqlgen.c @@ -1016,6 +1016,12 @@ struct db_query db_sqlite3_queries[] = { .placeholders = 0, .readonly = false, }, + { + .name = "ALTER TABLE outputs ADD csv_lock INTEGER DEFAULT 1;", + .query = "ALTER TABLE outputs ADD csv_lock INTEGER DEFAULT 1;", + .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 = ?", @@ -1269,26 +1275,26 @@ struct db_query db_sqlite3_queries[] = { .readonly = false, }, { - .name = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til FROM outputs", - .query = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til FROM outputs", + .name = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til , csv_lock FROM outputs", + .query = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til , csv_lock FROM outputs", .placeholders = 0, .readonly = true, }, { - .name = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til FROM outputs WHERE status= ? ", - .query = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til FROM outputs WHERE status= ? ", + .name = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til , csv_lock FROM outputs WHERE status= ? ", + .query = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til , csv_lock FROM outputs WHERE status= ? ", .placeholders = 1, .readonly = true, }, { - .name = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey, reserved_til FROM outputs WHERE channel_id IS NOT NULL AND confirmation_height IS NULL", - .query = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey, reserved_til FROM outputs WHERE channel_id IS NOT NULL AND confirmation_height IS NULL", + .name = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey, reserved_til, csv_lock FROM outputs WHERE channel_id IS NOT NULL AND confirmation_height IS NULL", + .query = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey, reserved_til, csv_lock FROM outputs WHERE channel_id IS NOT NULL AND confirmation_height IS NULL", .placeholders = 0, .readonly = true, }, { - .name = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey, reserved_til FROM outputs WHERE prev_out_tx = ? AND prev_out_index = ?", - .query = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey, reserved_til FROM outputs WHERE prev_out_tx = ? AND prev_out_index = ?", + .name = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey, reserved_til, csv_lock FROM outputs WHERE prev_out_tx = ? AND prev_out_index = ?", + .query = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey, reserved_til, csv_lock FROM outputs WHERE prev_out_tx = ? AND prev_out_index = ?", .placeholders = 2, .readonly = true, }, @@ -1299,11 +1305,17 @@ struct db_query db_sqlite3_queries[] = { .readonly = false, }, { - .name = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til FROM outputs WHERE status = ? OR (status = ? AND reserved_til <= ?)ORDER BY RANDOM();", - .query = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til FROM outputs WHERE status = ? OR (status = ? AND reserved_til <= ?)ORDER BY RANDOM();", + .name = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til, csv_lock FROM outputs WHERE status = ? OR (status = ? AND reserved_til <= ?)ORDER BY RANDOM();", + .query = "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til, csv_lock FROM outputs WHERE status = ? OR (status = ? AND reserved_til <= ?)ORDER BY RANDOM();", .placeholders = 3, .readonly = true, }, + { + .name = "INSERT INTO outputs ( prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey, csv_lock) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", + .query = "INSERT INTO outputs ( prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey, csv_lock) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", + .placeholders = 14, + .readonly = false, + }, { .name = "INSERT INTO shachains (min_index, num_valid) VALUES (?, 0);", .query = "INSERT INTO shachains (min_index, num_valid) VALUES (?, 0);", @@ -2008,10 +2020,10 @@ struct db_query db_sqlite3_queries[] = { }, }; -#define DB_SQLITE3_QUERY_COUNT 333 +#define DB_SQLITE3_QUERY_COUNT 335 #endif /* HAVE_SQLITE3 */ #endif /* LIGHTNINGD_WALLET_GEN_DB_SQLITE3 */ -// SHA256STAMP:7ec26901d6eff90c74fbac8885e3403b52e5555a161bf21cedcec8b5d62457e4 +// SHA256STAMP:7969d7dbe623730766408455852a9ca4394f05129258c8ebe7ffbdc47c5359b1 diff --git a/wallet/reservation.c b/wallet/reservation.c index 7ca74557dccb..96f90808db03 100644 --- a/wallet/reservation.c +++ b/wallet/reservation.c @@ -287,7 +287,7 @@ static struct wally_psbt *psbt_using_utxos(const tal_t *ctx, */ if (utxos[i]->close_info && utxos[i]->close_info->option_anchor_outputs) - this_nsequence = 1; + this_nsequence = utxos[i]->close_info->csv; else this_nsequence = nsequence; diff --git a/wallet/statements_gettextgen.po b/wallet/statements_gettextgen.po index 11148525c378..6bf28b1fa26a 100644 --- a/wallet/statements_gettextgen.po +++ b/wallet/statements_gettextgen.po @@ -670,91 +670,95 @@ msgstr "" msgid "CREATE TABLE channel_blockheights ( channel_id BIGINT REFERENCES channels(id) ON DELETE CASCADE, hstate INTEGER, blockheight INTEGER, UNIQUE (channel_id, hstate));" msgstr "" -#: wallet/db.c:977 +#: wallet/db.c:751 +msgid "ALTER TABLE outputs ADD csv_lock INTEGER DEFAULT 1;" +msgstr "" + +#: wallet/db.c:978 msgid "UPDATE vars SET intval = intval + 1 WHERE name = 'data_version' AND intval = ?" msgstr "" -#: wallet/db.c:1077 +#: wallet/db.c:1078 msgid "SELECT version FROM version LIMIT 1" msgstr "" -#: wallet/db.c:1139 +#: wallet/db.c:1140 msgid "UPDATE version SET version=?;" msgstr "" -#: wallet/db.c:1147 +#: wallet/db.c:1148 msgid "INSERT INTO db_upgrades VALUES (?, ?);" msgstr "" -#: wallet/db.c:1159 +#: wallet/db.c:1160 msgid "SELECT intval FROM vars WHERE name = 'data_version'" msgstr "" -#: wallet/db.c:1186 +#: wallet/db.c:1187 msgid "SELECT intval FROM vars WHERE name= ? LIMIT 1" msgstr "" -#: wallet/db.c:1202 +#: wallet/db.c:1203 msgid "UPDATE vars SET intval=? WHERE name=?;" msgstr "" -#: wallet/db.c:1211 +#: wallet/db.c:1212 msgid "INSERT INTO vars (name, intval) VALUES (?, ?);" msgstr "" -#: wallet/db.c:1225 +#: wallet/db.c:1226 msgid "UPDATE channels SET feerate_base = ?, feerate_ppm = ?;" msgstr "" -#: wallet/db.c:1246 +#: wallet/db.c:1247 msgid "UPDATE channels SET our_funding_satoshi = funding_satoshi WHERE funder = 0;" msgstr "" -#: wallet/db.c:1262 +#: wallet/db.c:1263 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:1324 +#: wallet/db.c:1325 msgid "UPDATE outputs SET scriptpubkey = ? WHERE prev_out_tx = ? AND prev_out_index = ?" msgstr "" -#: wallet/db.c:1349 +#: wallet/db.c:1350 msgid "SELECT id, funding_tx_id, funding_tx_outnum FROM channels;" msgstr "" -#: wallet/db.c:1368 +#: wallet/db.c:1369 msgid "UPDATE channels SET full_channel_id = ? WHERE id = ?;" msgstr "" -#: wallet/db.c:1389 +#: wallet/db.c:1390 msgid "SELECT channels.id, peers.node_id FROM channels JOIN peers ON (peers.id = channels.peer_id)" msgstr "" -#: wallet/db.c:1422 +#: wallet/db.c:1423 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:1455 +#: wallet/db.c:1456 msgid "INSERT INTO channel_blockheights (channel_id, hstate, blockheight) SELECT id, 4, 0 FROM channels WHERE funder = 0;" msgstr "" -#: wallet/db.c:1463 +#: wallet/db.c:1464 msgid "INSERT INTO channel_blockheights (channel_id, hstate, blockheight) SELECT id, 14, 0 FROM channels WHERE funder = 1;" msgstr "" -#: wallet/db.c:1475 +#: wallet/db.c:1476 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:1542 +#: wallet/db.c:1543 msgid "UPDATE channel_funding_inflights SET last_tx = ? WHERE channel_id = ? AND funding_tx_id = ?;" msgstr "" -#: wallet/db.c:1566 +#: wallet/db.c:1567 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:1633 +#: wallet/db.c:1634 msgid "UPDATE channels SET last_tx = ? WHERE id = ?;" msgstr "" @@ -822,495 +826,499 @@ msgstr "" msgid "SELECT txid, outnum FROM utxoset WHERE spendheight is NULL" msgstr "" -#: wallet/wallet.c:107 wallet/wallet.c:589 +#: wallet/wallet.c:107 wallet/wallet.c:596 msgid "SELECT * from outputs WHERE prev_out_tx=? AND prev_out_index=?" msgstr "" -#: wallet/wallet.c:121 wallet/wallet.c:603 +#: wallet/wallet.c:121 msgid "INSERT INTO outputs ( prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:238 +#: wallet/wallet.c:239 msgid "UPDATE outputs SET status=? WHERE status=? AND prev_out_tx=? AND prev_out_index=?" msgstr "" -#: wallet/wallet.c:246 +#: wallet/wallet.c:247 msgid "UPDATE outputs SET status=? WHERE prev_out_tx=? AND prev_out_index=?" msgstr "" -#: wallet/wallet.c:265 -msgid "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til FROM outputs" +#: wallet/wallet.c:266 +msgid "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til , csv_lock FROM outputs" msgstr "" -#: wallet/wallet.c:282 -msgid "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til FROM outputs WHERE status= ? " +#: wallet/wallet.c:284 +msgid "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til , csv_lock FROM outputs WHERE status= ? " msgstr "" -#: wallet/wallet.c:320 -msgid "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey, reserved_til FROM outputs WHERE channel_id IS NOT NULL AND confirmation_height IS NULL" +#: wallet/wallet.c:323 +msgid "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey, reserved_til, csv_lock FROM outputs WHERE channel_id IS NOT NULL AND confirmation_height IS NULL" msgstr "" -#: wallet/wallet.c:357 -msgid "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey, reserved_til FROM outputs WHERE prev_out_tx = ? AND prev_out_index = ?" +#: wallet/wallet.c:361 +msgid "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey, reserved_til, csv_lock FROM outputs WHERE prev_out_tx = ? AND prev_out_index = ?" msgstr "" -#: wallet/wallet.c:449 +#: wallet/wallet.c:454 msgid "UPDATE outputs SET status=?, reserved_til=? WHERE prev_out_tx=? AND prev_out_index=?" msgstr "" -#: wallet/wallet.c:538 -msgid "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til FROM outputs WHERE status = ? OR (status = ? AND reserved_til <= ?)ORDER BY RANDOM();" +#: wallet/wallet.c:543 +msgid "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til, csv_lock FROM outputs WHERE status = ? OR (status = ? AND reserved_til <= ?)ORDER BY RANDOM();" +msgstr "" + +#: wallet/wallet.c:610 +msgid "INSERT INTO outputs ( prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey, csv_lock) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:707 +#: wallet/wallet.c:717 msgid "INSERT INTO shachains (min_index, num_valid) VALUES (?, 0);" msgstr "" -#: wallet/wallet.c:751 +#: wallet/wallet.c:761 msgid "UPDATE shachains SET num_valid=?, min_index=? WHERE id=?" msgstr "" -#: wallet/wallet.c:758 +#: wallet/wallet.c:768 msgid "UPDATE shachain_known SET idx=?, hash=? WHERE shachain_id=? AND pos=?" msgstr "" -#: wallet/wallet.c:770 +#: wallet/wallet.c:780 msgid "INSERT INTO shachain_known (shachain_id, pos, idx, hash) VALUES (?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:792 +#: wallet/wallet.c:802 msgid "SELECT min_index, num_valid FROM shachains WHERE id=?" msgstr "" -#: wallet/wallet.c:807 +#: wallet/wallet.c:817 msgid "SELECT idx, hash, pos FROM shachain_known WHERE shachain_id=?" msgstr "" -#: wallet/wallet.c:830 +#: wallet/wallet.c:840 msgid "SELECT id, node_id, address FROM peers WHERE id=?;" msgstr "" -#: wallet/wallet.c:863 +#: wallet/wallet.c:873 msgid "SELECT signature FROM htlc_sigs WHERE channelid = ?" msgstr "" -#: wallet/wallet.c:897 +#: wallet/wallet.c:907 msgid "SELECT remote_ann_node_sig, remote_ann_bitcoin_sig FROM channels WHERE id = ?" msgstr "" -#: wallet/wallet.c:941 +#: wallet/wallet.c:951 msgid "SELECT hstate, feerate_per_kw FROM channel_feerates WHERE channel_id = ?" msgstr "" -#: wallet/wallet.c:977 +#: wallet/wallet.c:987 msgid "SELECT hstate, blockheight FROM channel_blockheights WHERE channel_id = ?" msgstr "" -#: wallet/wallet.c:1010 +#: wallet/wallet.c:1020 msgid "INSERT INTO channel_funding_inflights ( channel_id, funding_tx_id, funding_tx_outnum, funding_feerate, funding_satoshi, our_funding_satoshi, funding_psbt, last_tx, last_sig, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt, lease_expiry, lease_blockheight_start) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:1066 +#: wallet/wallet.c:1076 msgid "UPDATE channel_funding_inflights SET funding_psbt=?, funding_tx_remote_sigs_received=? WHERE channel_id=? AND funding_tx_id=? AND funding_tx_outnum=?" msgstr "" -#: wallet/wallet.c:1089 +#: wallet/wallet.c:1099 msgid "DELETE FROM channel_funding_inflights WHERE channel_id = ?" msgstr "" -#: wallet/wallet.c:1159 +#: wallet/wallet.c:1169 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, lease_expiry, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt, lease_blockheight_start FROM channel_funding_inflights WHERE channel_id = ? ORDER BY funding_feerate" msgstr "" -#: wallet/wallet.c:1427 +#: wallet/wallet.c:1437 msgid "SELECT id FROM channels ORDER BY id DESC LIMIT 1;" msgstr "" -#: wallet/wallet.c:1444 +#: wallet/wallet.c:1454 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, lease_expiry, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt FROM channels WHERE state != ?;" msgstr "" -#: wallet/wallet.c:1556 +#: wallet/wallet.c:1566 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:1562 +#: wallet/wallet.c:1572 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:1568 +#: wallet/wallet.c:1578 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:1574 +#: wallet/wallet.c:1584 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:1619 +#: wallet/wallet.c:1629 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:1648 +#: wallet/wallet.c:1658 msgid "SELECT MIN(height), MAX(height) FROM blocks;" msgstr "" -#: wallet/wallet.c:1670 +#: wallet/wallet.c:1680 msgid "INSERT INTO channel_configs DEFAULT VALUES;" msgstr "" -#: wallet/wallet.c:1682 +#: wallet/wallet.c:1692 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:1706 +#: wallet/wallet.c:1716 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:1740 +#: wallet/wallet.c:1750 msgid "UPDATE channels SET remote_ann_node_sig=?, remote_ann_bitcoin_sig=? WHERE id=?" msgstr "" -#: wallet/wallet.c:1759 +#: wallet/wallet.c:1769 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=?, lease_expiry=?, lease_commit_sig=?, lease_chan_max_msat=?, lease_chan_max_ppt=? WHERE id=?" msgstr "" -#: wallet/wallet.c:1868 +#: wallet/wallet.c:1878 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:1895 +#: wallet/wallet.c:1905 msgid "DELETE FROM channel_feerates WHERE channel_id=?" msgstr "" -#: wallet/wallet.c:1905 +#: wallet/wallet.c:1915 msgid "INSERT INTO channel_feerates VALUES(?, ?, ?)" msgstr "" -#: wallet/wallet.c:1914 +#: wallet/wallet.c:1924 msgid "DELETE FROM channel_blockheights WHERE channel_id=?" msgstr "" -#: wallet/wallet.c:1924 +#: wallet/wallet.c:1934 msgid "INSERT INTO channel_blockheights VALUES(?, ?, ?)" msgstr "" -#: wallet/wallet.c:1941 +#: wallet/wallet.c:1951 msgid "UPDATE channels SET last_sent_commit=? WHERE id=?" msgstr "" -#: wallet/wallet.c:1964 +#: wallet/wallet.c:1974 msgid "INSERT INTO channel_state_changes ( channel_id, timestamp, old_state, new_state, cause, message) VALUES (?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:1992 +#: wallet/wallet.c:2002 msgid "SELECT timestamp, old_state, new_state, cause, message FROM channel_state_changes WHERE channel_id = ? ORDER BY timestamp ASC;" msgstr "" -#: wallet/wallet.c:2021 +#: wallet/wallet.c:2031 msgid "SELECT id FROM peers WHERE node_id = ?" msgstr "" -#: wallet/wallet.c:2033 +#: wallet/wallet.c:2043 msgid "UPDATE peers SET address = ? WHERE id = ?" msgstr "" -#: wallet/wallet.c:2042 +#: wallet/wallet.c:2052 msgid "INSERT INTO peers (node_id, address) VALUES (?, ?);" msgstr "" -#: wallet/wallet.c:2063 +#: wallet/wallet.c:2073 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:2104 +#: wallet/wallet.c:2114 msgid "DELETE FROM channel_htlcs WHERE channel_id=?" msgstr "" -#: wallet/wallet.c:2110 +#: wallet/wallet.c:2120 msgid "DELETE FROM htlc_sigs WHERE channelid=?" msgstr "" -#: wallet/wallet.c:2116 +#: wallet/wallet.c:2126 msgid "DELETE FROM channeltxs WHERE channel_id=?" msgstr "" -#: wallet/wallet.c:2123 +#: wallet/wallet.c:2133 msgid "DELETE FROM channel_funding_inflights WHERE channel_id=?" msgstr "" -#: wallet/wallet.c:2129 +#: wallet/wallet.c:2139 msgid "DELETE FROM shachains WHERE id IN ( SELECT shachain_remote_id FROM channels WHERE channels.id=?)" msgstr "" -#: wallet/wallet.c:2139 +#: wallet/wallet.c:2149 msgid "UPDATE channels SET state=?, peer_id=? WHERE channels.id=?" msgstr "" -#: wallet/wallet.c:2153 +#: wallet/wallet.c:2163 msgid "SELECT * FROM channels WHERE peer_id = ?;" msgstr "" -#: wallet/wallet.c:2161 +#: wallet/wallet.c:2171 msgid "DELETE FROM peers WHERE id=?" msgstr "" -#: wallet/wallet.c:2172 +#: wallet/wallet.c:2182 msgid "UPDATE outputs SET confirmation_height = ? WHERE prev_out_tx = ?" msgstr "" -#: wallet/wallet.c:2275 +#: wallet/wallet.c:2285 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:2328 +#: wallet/wallet.c:2338 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:2389 +#: wallet/wallet.c:2399 msgid "UPDATE channel_htlcs SET hstate=?, payment_key=?, malformed_onion=?, failuremsg=?, localfailmsg=?, we_filled=? WHERE id=?" msgstr "" -#: wallet/wallet.c:2606 +#: wallet/wallet.c:2616 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:2653 +#: wallet/wallet.c:2663 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:2784 +#: wallet/wallet.c:2794 msgid "SELECT channel_id, direction, cltv_expiry, channel_htlc_id, payment_hash FROM channel_htlcs WHERE channel_id = ?;" msgstr "" -#: wallet/wallet.c:2818 +#: wallet/wallet.c:2828 msgid "DELETE FROM channel_htlcs WHERE direction = ? AND origin_htlc = ? AND payment_hash = ? AND partid = ?;" msgstr "" -#: wallet/wallet.c:2871 +#: wallet/wallet.c:2881 msgid "SELECT status FROM payments WHERE payment_hash=? AND partid = ?;" msgstr "" -#: wallet/wallet.c:2889 +#: wallet/wallet.c:2899 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:2978 +#: wallet/wallet.c:2988 msgid "DELETE FROM payments WHERE payment_hash = ? AND partid = ?" msgstr "" -#: wallet/wallet.c:2992 +#: wallet/wallet.c:3002 msgid "DELETE FROM payments WHERE payment_hash = ?" msgstr "" -#: wallet/wallet.c:3093 +#: wallet/wallet.c:3103 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:3143 +#: wallet/wallet.c:3153 msgid "UPDATE payments SET status=? WHERE payment_hash=? AND partid=?" msgstr "" -#: wallet/wallet.c:3153 +#: wallet/wallet.c:3163 msgid "UPDATE payments SET payment_preimage=? WHERE payment_hash=? AND partid=?" msgstr "" -#: wallet/wallet.c:3163 +#: wallet/wallet.c:3173 msgid "UPDATE payments SET path_secrets = NULL , route_nodes = NULL , route_channels = NULL WHERE payment_hash = ? AND partid = ?;" msgstr "" -#: wallet/wallet.c:3195 +#: wallet/wallet.c:3205 msgid "SELECT failonionreply, faildestperm, failindex, failcode, failnode, failchannel, failupdate, faildetail, faildirection FROM payments WHERE payment_hash=? AND partid=?;" msgstr "" -#: wallet/wallet.c:3262 +#: wallet/wallet.c:3272 msgid "UPDATE payments SET failonionreply=? , faildestperm=? , failindex=? , failcode=? , failnode=? , failchannel=? , failupdate=? , faildetail=? , faildirection=? WHERE payment_hash=? AND partid=?;" msgstr "" -#: wallet/wallet.c:3321 +#: wallet/wallet.c:3331 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:3344 +#: wallet/wallet.c:3354 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:3395 +#: wallet/wallet.c:3405 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:3440 +#: wallet/wallet.c:3450 msgid "DELETE FROM htlc_sigs WHERE channelid = ?" msgstr "" -#: wallet/wallet.c:3447 +#: wallet/wallet.c:3457 msgid "INSERT INTO htlc_sigs (channelid, signature) VALUES (?, ?)" msgstr "" -#: wallet/wallet.c:3459 +#: wallet/wallet.c:3469 msgid "SELECT blobval FROM vars WHERE name='genesis_hash'" msgstr "" -#: wallet/wallet.c:3483 +#: wallet/wallet.c:3493 msgid "INSERT INTO vars (name, blobval) VALUES ('genesis_hash', ?);" msgstr "" -#: wallet/wallet.c:3501 +#: wallet/wallet.c:3511 msgid "SELECT txid, outnum FROM utxoset WHERE spendheight < ?" msgstr "" -#: wallet/wallet.c:3513 +#: wallet/wallet.c:3523 msgid "DELETE FROM utxoset WHERE spendheight < ?" msgstr "" -#: wallet/wallet.c:3521 wallet/wallet.c:3635 +#: wallet/wallet.c:3531 wallet/wallet.c:3645 msgid "INSERT INTO blocks (height, hash, prev_hash) VALUES (?, ?, ?);" msgstr "" -#: wallet/wallet.c:3540 +#: wallet/wallet.c:3550 msgid "DELETE FROM blocks WHERE hash = ?" msgstr "" -#: wallet/wallet.c:3546 +#: wallet/wallet.c:3556 msgid "SELECT * FROM blocks WHERE height >= ?;" msgstr "" -#: wallet/wallet.c:3555 +#: wallet/wallet.c:3565 msgid "DELETE FROM blocks WHERE height > ?" msgstr "" -#: wallet/wallet.c:3567 +#: wallet/wallet.c:3577 msgid "UPDATE outputs SET spend_height = ?, status = ? WHERE prev_out_tx = ? AND prev_out_index = ?" msgstr "" -#: wallet/wallet.c:3585 +#: wallet/wallet.c:3595 msgid "UPDATE utxoset SET spendheight = ? WHERE txid = ? AND outnum = ?" msgstr "" -#: wallet/wallet.c:3608 wallet/wallet.c:3646 +#: wallet/wallet.c:3618 wallet/wallet.c:3656 msgid "INSERT INTO utxoset ( txid, outnum, blockheight, spendheight, txindex, scriptpubkey, satoshis) VALUES(?, ?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:3672 +#: wallet/wallet.c:3682 msgid "SELECT height FROM blocks WHERE height = ?" msgstr "" -#: wallet/wallet.c:3685 +#: wallet/wallet.c:3695 msgid "SELECT txid, spendheight, scriptpubkey, satoshis FROM utxoset WHERE blockheight = ? AND txindex = ? AND outnum = ? AND spendheight IS NULL" msgstr "" -#: wallet/wallet.c:3727 +#: wallet/wallet.c:3737 msgid "SELECT blockheight, txindex, outnum FROM utxoset WHERE spendheight = ?" msgstr "" -#: wallet/wallet.c:3758 wallet/wallet.c:3918 +#: wallet/wallet.c:3768 wallet/wallet.c:3928 msgid "SELECT blockheight FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3768 +#: wallet/wallet.c:3778 msgid "INSERT INTO transactions ( id, blockheight, txindex, rawtx) VALUES (?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:3789 +#: wallet/wallet.c:3799 msgid "UPDATE transactions SET blockheight = ?, txindex = ? WHERE id = ?" msgstr "" -#: wallet/wallet.c:3806 +#: wallet/wallet.c:3816 msgid "INSERT INTO transaction_annotations (txid, idx, location, type, channel) VALUES (?, ?, ?, ?, ?) ON CONFLICT(txid,idx) DO NOTHING;" msgstr "" -#: wallet/wallet.c:3838 +#: wallet/wallet.c:3848 msgid "SELECT type, channel_id FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3854 +#: wallet/wallet.c:3864 msgid "UPDATE transactions SET type = ?, channel_id = ? WHERE id = ?" msgstr "" -#: wallet/wallet.c:3873 +#: wallet/wallet.c:3883 msgid "SELECT type FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3896 +#: wallet/wallet.c:3906 msgid "SELECT rawtx FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3942 +#: wallet/wallet.c:3952 msgid "SELECT blockheight, txindex FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3970 +#: wallet/wallet.c:3980 msgid "SELECT id FROM transactions WHERE blockheight=?" msgstr "" -#: wallet/wallet.c:3989 +#: wallet/wallet.c:3999 msgid "INSERT INTO channeltxs ( channel_id, type, transaction_id, input_num, blockheight) VALUES (?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:4013 +#: wallet/wallet.c:4023 msgid "SELECT DISTINCT(channel_id) FROM channeltxs WHERE type = ?;" msgstr "" -#: wallet/wallet.c:4034 +#: wallet/wallet.c:4044 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:4079 +#: wallet/wallet.c:4089 msgid "UPDATE forwarded_payments SET in_msatoshi=?, out_msatoshi=?, state=?, resolved_time=?, failcode=? WHERE in_htlc_id=?" msgstr "" -#: wallet/wallet.c:4137 +#: wallet/wallet.c:4147 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:4196 +#: wallet/wallet.c:4206 msgid "SELECT CAST(COALESCE(SUM(in_msatoshi - out_msatoshi), 0) AS BIGINT)FROM forwarded_payments WHERE state = ?;" msgstr "" -#: wallet/wallet.c:4245 +#: wallet/wallet.c:4255 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:4367 +#: wallet/wallet.c:4377 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:4461 +#: wallet/wallet.c:4471 msgid "INSERT INTO penalty_bases ( channel_id, commitnum, txid, outnum, amount) VALUES (?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:4486 +#: wallet/wallet.c:4496 msgid "SELECT commitnum, txid, outnum, amount FROM penalty_bases WHERE channel_id = ?" msgstr "" -#: wallet/wallet.c:4510 +#: wallet/wallet.c:4520 msgid "DELETE FROM penalty_bases WHERE channel_id = ? AND commitnum = ?" msgstr "" -#: wallet/wallet.c:4528 +#: wallet/wallet.c:4538 msgid "SELECT 1 FROM offers WHERE offer_id = ?;" msgstr "" -#: wallet/wallet.c:4541 +#: wallet/wallet.c:4551 msgid "INSERT INTO offers ( offer_id, bolt12, label, status) VALUES (?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:4568 +#: wallet/wallet.c:4578 msgid "SELECT bolt12, label, status FROM offers WHERE offer_id = ?;" msgstr "" -#: wallet/wallet.c:4596 +#: wallet/wallet.c:4606 msgid "SELECT offer_id FROM offers;" msgstr "" -#: wallet/wallet.c:4622 +#: wallet/wallet.c:4632 msgid "UPDATE offers SET status=? WHERE offer_id = ?;" msgstr "" -#: wallet/wallet.c:4633 +#: wallet/wallet.c:4643 msgid "UPDATE invoices SET state=? WHERE state=? AND local_offer_id = ?;" msgstr "" -#: wallet/wallet.c:4661 +#: wallet/wallet.c:4671 msgid "SELECT status FROM offers WHERE offer_id = ?;" msgstr "" @@ -1329,4 +1337,4 @@ msgstr "" #: wallet/test/run-wallet.c:1696 msgid "INSERT INTO channels (id) VALUES (1);" msgstr "" -# SHA256STAMP:961e19c597842de7935718de7979b986804b3c99078d3c4792b7fb76d7405217 +# SHA256STAMP:c1ab278c0d0e353eaf62f3c02566a42bdc65443fae40eebe182c11f3fd51abef diff --git a/wallet/wallet.c b/wallet/wallet.c index fd86fd208245..e23f3d32aebb 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -197,6 +197,7 @@ static struct utxo *wallet_stmt2output(const tal_t *ctx, struct db_stmt *stmt) utxo->close_info->commitment_point = NULL; utxo->close_info->option_anchor_outputs = db_column_int(stmt, 9); + utxo->close_info->csv = db_column_int(stmt, 14); } else { utxo->close_info = NULL; } @@ -277,6 +278,7 @@ struct utxo **wallet_get_utxos(const tal_t *ctx, struct wallet *w, const enum ou ", spend_height" ", scriptpubkey " ", reserved_til " + ", csv_lock " "FROM outputs")); } else { stmt = db_prepare_v2(w->db, SQL("SELECT" @@ -294,6 +296,7 @@ struct utxo **wallet_get_utxos(const tal_t *ctx, struct wallet *w, const enum ou ", spend_height" ", scriptpubkey " ", reserved_til " + ", csv_lock " "FROM outputs " "WHERE status= ? ")); db_bind_int(stmt, 0, output_status_in_db(state)); @@ -332,6 +335,7 @@ struct utxo **wallet_get_unconfirmed_closeinfo_utxos(const tal_t *ctx, ", spend_height" ", scriptpubkey" ", reserved_til" + ", csv_lock" " FROM outputs" " WHERE channel_id IS NOT NULL AND " "confirmation_height IS NULL")); @@ -369,6 +373,7 @@ struct utxo *wallet_utxo_get(const tal_t *ctx, struct wallet *w, ", spend_height" ", scriptpubkey" ", reserved_til" + ", csv_lock" " FROM outputs" " WHERE prev_out_tx = ?" " AND prev_out_index = ?")); @@ -550,6 +555,7 @@ struct utxo *wallet_find_utxo(const tal_t *ctx, struct wallet *w, ", spend_height" ", scriptpubkey " ", reserved_til" + ", csv_lock" " FROM outputs" " WHERE status = ?" " OR (status = ? AND reserved_til <= ?)" @@ -582,7 +588,8 @@ bool wallet_add_onchaind_utxo(struct wallet *w, struct amount_sat amount, const struct channel *channel, /* NULL if option_static_remotekey */ - const struct pubkey *commitment_point) + const struct pubkey *commitment_point, + u32 csv_lock) { struct db_stmt *stmt; @@ -614,7 +621,8 @@ bool wallet_add_onchaind_utxo(struct wallet *w, ", confirmation_height" ", spend_height" ", scriptpubkey" - ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);")); + ", csv_lock" + ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);")); db_bind_txid(stmt, 0, txid); db_bind_int(stmt, 1, outnum); db_bind_amount_sat(stmt, 2, &amount); @@ -635,6 +643,8 @@ bool wallet_add_onchaind_utxo(struct wallet *w, db_bind_null(stmt, 11); db_bind_blob(stmt, 12, scriptpubkey, tal_bytelen(scriptpubkey)); + db_bind_int(stmt, 13, csv_lock); + db_exec_prepared_v2(take(stmt)); return true; } diff --git a/wallet/wallet.h b/wallet/wallet.h index d8b399385477..f25881696806 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -400,7 +400,9 @@ bool wallet_add_onchaind_utxo(struct wallet *w, struct amount_sat amount, const struct channel *chan, /* NULL if option_static_remotekey */ - const struct pubkey *commitment_point); + const struct pubkey *commitment_point, + /* option_will_fund makes the csv_lock variable */ + u32 csv_lock); /** * wallet_reserve_utxo - set a reservation on a UTXO. diff --git a/wallet/walletrpc.c b/wallet/walletrpc.c index 8bf0f6ccea0c..08abb1b125d3 100644 --- a/wallet/walletrpc.c +++ b/wallet/walletrpc.c @@ -291,6 +291,14 @@ static void json_add_utxo(struct json_stream *response, if (reserved) json_add_num(response, "reserved_to_block", utxo->reserved_til); + if (utxo->close_info && utxo->close_info->csv > 1) { + json_add_num(response, "csv_lock", utxo->close_info->csv); + + if (utxo->blockheight) + json_add_u32(response, "spendable_at", + *utxo->blockheight + utxo->close_info->csv); + } + json_object_end(response); } From 9955e5d6644e51a0726947fa7eb7b6ae09f4fcc1 Mon Sep 17 00:00:00 2001 From: niftynei Date: Fri, 2 Jul 2021 14:56:35 -0500 Subject: [PATCH 38/56] utxo: don't add outputs that aren't currently eligible to be spent If an output's CSV lock hasn't been surpassed yet, don't try to include it in a transaction --- common/utxo.h | 12 ++ wallet/db_postgres_sqlgen.c | 2 +- wallet/db_sqlite3_sqlgen.c | 2 +- wallet/reservation.c | 9 ++ wallet/statements_gettextgen.po | 234 ++++++++++++++++---------------- wallet/wallet.c | 13 +- 6 files changed, 151 insertions(+), 121 deletions(-) diff --git a/common/utxo.h b/common/utxo.h index 2f3c63764b8f..11910af5b07f 100644 --- a/common/utxo.h +++ b/common/utxo.h @@ -1,6 +1,7 @@ #ifndef LIGHTNING_COMMON_UTXO_H #define LIGHTNING_COMMON_UTXO_H #include "config.h" +#include #include #include #include @@ -71,6 +72,17 @@ static inline bool utxo_is_reserved(const struct utxo *utxo, u32 current_height) return utxo->reserved_til > current_height; } +static inline bool utxo_is_csv_locked(const struct utxo *utxo, u32 current_height) +{ + if (!utxo->close_info) + return false; + /* All close outputs are csv locked for option_anchor_outputs */ + if (!utxo->blockheight && utxo->close_info->option_anchor_outputs) + return true; + assert(*utxo->blockheight + utxo->close_info->csv > *utxo->blockheight); + return *utxo->blockheight + utxo->close_info->csv > current_height; +} + void towire_utxo(u8 **pptr, const struct utxo *utxo); struct utxo *fromwire_utxo(const tal_t *ctx, const u8 **ptr, size_t *max); diff --git a/wallet/db_postgres_sqlgen.c b/wallet/db_postgres_sqlgen.c index f532c90e77ff..3f37ce43e430 100644 --- a/wallet/db_postgres_sqlgen.c +++ b/wallet/db_postgres_sqlgen.c @@ -2026,4 +2026,4 @@ struct db_query db_postgres_queries[] = { #endif /* LIGHTNINGD_WALLET_GEN_DB_POSTGRES */ -// SHA256STAMP:7969d7dbe623730766408455852a9ca4394f05129258c8ebe7ffbdc47c5359b1 +// SHA256STAMP:4d1da328c12739465826fac14dfba853b845ee1c752626f1767ef52a79471de7 diff --git a/wallet/db_sqlite3_sqlgen.c b/wallet/db_sqlite3_sqlgen.c index 7e44b6638720..e8699aede551 100644 --- a/wallet/db_sqlite3_sqlgen.c +++ b/wallet/db_sqlite3_sqlgen.c @@ -2026,4 +2026,4 @@ struct db_query db_sqlite3_queries[] = { #endif /* LIGHTNINGD_WALLET_GEN_DB_SQLITE3 */ -// SHA256STAMP:7969d7dbe623730766408455852a9ca4394f05129258c8ebe7ffbdc47c5359b1 +// SHA256STAMP:4d1da328c12739465826fac14dfba853b845ee1c752626f1767ef52a79471de7 diff --git a/wallet/reservation.c b/wallet/reservation.c index 96f90808db03..84e5e3beef07 100644 --- a/wallet/reservation.c +++ b/wallet/reservation.c @@ -682,6 +682,15 @@ static struct command_result *json_utxopsbt(struct command *cmd, struct bitcoin_txid, &utxo->txid), utxo->outnum); + if (utxo_is_csv_locked(utxo, current_height)) + return command_fail(cmd, JSONRPC2_INVALID_PARAMS, + "UTXO %s:%u is csv locked (%u)", + type_to_string(tmpctx, + struct bitcoin_txid, + &utxo->txid), + utxo->outnum, + utxo->close_info->csv); + /* It supplies more input. */ if (!amount_sat_add(&input, input, utxo->amount)) diff --git a/wallet/statements_gettextgen.po b/wallet/statements_gettextgen.po index 6bf28b1fa26a..4554b8cc91b3 100644 --- a/wallet/statements_gettextgen.po +++ b/wallet/statements_gettextgen.po @@ -826,7 +826,7 @@ msgstr "" msgid "SELECT txid, outnum FROM utxoset WHERE spendheight is NULL" msgstr "" -#: wallet/wallet.c:107 wallet/wallet.c:596 +#: wallet/wallet.c:107 wallet/wallet.c:605 msgid "SELECT * from outputs WHERE prev_out_tx=? AND prev_out_index=?" msgstr "" @@ -862,463 +862,463 @@ msgstr "" msgid "UPDATE outputs SET status=?, reserved_til=? WHERE prev_out_tx=? AND prev_out_index=?" msgstr "" -#: wallet/wallet.c:543 +#: wallet/wallet.c:551 msgid "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey , reserved_til, csv_lock FROM outputs WHERE status = ? OR (status = ? AND reserved_til <= ?)ORDER BY RANDOM();" msgstr "" -#: wallet/wallet.c:610 +#: wallet/wallet.c:619 msgid "INSERT INTO outputs ( prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point, option_anchor_outputs, confirmation_height, spend_height, scriptpubkey, csv_lock) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:717 +#: wallet/wallet.c:726 msgid "INSERT INTO shachains (min_index, num_valid) VALUES (?, 0);" msgstr "" -#: wallet/wallet.c:761 +#: wallet/wallet.c:770 msgid "UPDATE shachains SET num_valid=?, min_index=? WHERE id=?" msgstr "" -#: wallet/wallet.c:768 +#: wallet/wallet.c:777 msgid "UPDATE shachain_known SET idx=?, hash=? WHERE shachain_id=? AND pos=?" msgstr "" -#: wallet/wallet.c:780 +#: wallet/wallet.c:789 msgid "INSERT INTO shachain_known (shachain_id, pos, idx, hash) VALUES (?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:802 +#: wallet/wallet.c:811 msgid "SELECT min_index, num_valid FROM shachains WHERE id=?" msgstr "" -#: wallet/wallet.c:817 +#: wallet/wallet.c:826 msgid "SELECT idx, hash, pos FROM shachain_known WHERE shachain_id=?" msgstr "" -#: wallet/wallet.c:840 +#: wallet/wallet.c:849 msgid "SELECT id, node_id, address FROM peers WHERE id=?;" msgstr "" -#: wallet/wallet.c:873 +#: wallet/wallet.c:882 msgid "SELECT signature FROM htlc_sigs WHERE channelid = ?" msgstr "" -#: wallet/wallet.c:907 +#: wallet/wallet.c:916 msgid "SELECT remote_ann_node_sig, remote_ann_bitcoin_sig FROM channels WHERE id = ?" msgstr "" -#: wallet/wallet.c:951 +#: wallet/wallet.c:960 msgid "SELECT hstate, feerate_per_kw FROM channel_feerates WHERE channel_id = ?" msgstr "" -#: wallet/wallet.c:987 +#: wallet/wallet.c:996 msgid "SELECT hstate, blockheight FROM channel_blockheights WHERE channel_id = ?" msgstr "" -#: wallet/wallet.c:1020 +#: wallet/wallet.c:1029 msgid "INSERT INTO channel_funding_inflights ( channel_id, funding_tx_id, funding_tx_outnum, funding_feerate, funding_satoshi, our_funding_satoshi, funding_psbt, last_tx, last_sig, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt, lease_expiry, lease_blockheight_start) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:1076 +#: wallet/wallet.c:1085 msgid "UPDATE channel_funding_inflights SET funding_psbt=?, funding_tx_remote_sigs_received=? WHERE channel_id=? AND funding_tx_id=? AND funding_tx_outnum=?" msgstr "" -#: wallet/wallet.c:1099 +#: wallet/wallet.c:1108 msgid "DELETE FROM channel_funding_inflights WHERE channel_id = ?" msgstr "" -#: wallet/wallet.c:1169 +#: wallet/wallet.c:1178 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, lease_expiry, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt, lease_blockheight_start FROM channel_funding_inflights WHERE channel_id = ? ORDER BY funding_feerate" msgstr "" -#: wallet/wallet.c:1437 +#: wallet/wallet.c:1446 msgid "SELECT id FROM channels ORDER BY id DESC LIMIT 1;" msgstr "" -#: wallet/wallet.c:1454 +#: wallet/wallet.c:1463 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, lease_expiry, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt FROM channels WHERE state != ?;" msgstr "" -#: wallet/wallet.c:1566 +#: wallet/wallet.c:1575 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:1572 +#: wallet/wallet.c:1581 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:1578 +#: wallet/wallet.c:1587 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:1584 +#: wallet/wallet.c:1593 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:1629 +#: wallet/wallet.c:1638 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:1658 +#: wallet/wallet.c:1667 msgid "SELECT MIN(height), MAX(height) FROM blocks;" msgstr "" -#: wallet/wallet.c:1680 +#: wallet/wallet.c:1689 msgid "INSERT INTO channel_configs DEFAULT VALUES;" msgstr "" -#: wallet/wallet.c:1692 +#: wallet/wallet.c:1701 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:1716 +#: wallet/wallet.c:1725 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:1750 +#: wallet/wallet.c:1759 msgid "UPDATE channels SET remote_ann_node_sig=?, remote_ann_bitcoin_sig=? WHERE id=?" msgstr "" -#: wallet/wallet.c:1769 +#: wallet/wallet.c:1778 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=?, lease_expiry=?, lease_commit_sig=?, lease_chan_max_msat=?, lease_chan_max_ppt=? WHERE id=?" msgstr "" -#: wallet/wallet.c:1878 +#: wallet/wallet.c:1887 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:1905 +#: wallet/wallet.c:1914 msgid "DELETE FROM channel_feerates WHERE channel_id=?" msgstr "" -#: wallet/wallet.c:1915 +#: wallet/wallet.c:1924 msgid "INSERT INTO channel_feerates VALUES(?, ?, ?)" msgstr "" -#: wallet/wallet.c:1924 +#: wallet/wallet.c:1933 msgid "DELETE FROM channel_blockheights WHERE channel_id=?" msgstr "" -#: wallet/wallet.c:1934 +#: wallet/wallet.c:1943 msgid "INSERT INTO channel_blockheights VALUES(?, ?, ?)" msgstr "" -#: wallet/wallet.c:1951 +#: wallet/wallet.c:1960 msgid "UPDATE channels SET last_sent_commit=? WHERE id=?" msgstr "" -#: wallet/wallet.c:1974 +#: wallet/wallet.c:1983 msgid "INSERT INTO channel_state_changes ( channel_id, timestamp, old_state, new_state, cause, message) VALUES (?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:2002 +#: wallet/wallet.c:2011 msgid "SELECT timestamp, old_state, new_state, cause, message FROM channel_state_changes WHERE channel_id = ? ORDER BY timestamp ASC;" msgstr "" -#: wallet/wallet.c:2031 +#: wallet/wallet.c:2040 msgid "SELECT id FROM peers WHERE node_id = ?" msgstr "" -#: wallet/wallet.c:2043 +#: wallet/wallet.c:2052 msgid "UPDATE peers SET address = ? WHERE id = ?" msgstr "" -#: wallet/wallet.c:2052 +#: wallet/wallet.c:2061 msgid "INSERT INTO peers (node_id, address) VALUES (?, ?);" msgstr "" -#: wallet/wallet.c:2073 +#: wallet/wallet.c:2082 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:2114 +#: wallet/wallet.c:2123 msgid "DELETE FROM channel_htlcs WHERE channel_id=?" msgstr "" -#: wallet/wallet.c:2120 +#: wallet/wallet.c:2129 msgid "DELETE FROM htlc_sigs WHERE channelid=?" msgstr "" -#: wallet/wallet.c:2126 +#: wallet/wallet.c:2135 msgid "DELETE FROM channeltxs WHERE channel_id=?" msgstr "" -#: wallet/wallet.c:2133 +#: wallet/wallet.c:2142 msgid "DELETE FROM channel_funding_inflights WHERE channel_id=?" msgstr "" -#: wallet/wallet.c:2139 +#: wallet/wallet.c:2148 msgid "DELETE FROM shachains WHERE id IN ( SELECT shachain_remote_id FROM channels WHERE channels.id=?)" msgstr "" -#: wallet/wallet.c:2149 +#: wallet/wallet.c:2158 msgid "UPDATE channels SET state=?, peer_id=? WHERE channels.id=?" msgstr "" -#: wallet/wallet.c:2163 +#: wallet/wallet.c:2172 msgid "SELECT * FROM channels WHERE peer_id = ?;" msgstr "" -#: wallet/wallet.c:2171 +#: wallet/wallet.c:2180 msgid "DELETE FROM peers WHERE id=?" msgstr "" -#: wallet/wallet.c:2182 +#: wallet/wallet.c:2191 msgid "UPDATE outputs SET confirmation_height = ? WHERE prev_out_tx = ?" msgstr "" -#: wallet/wallet.c:2285 +#: wallet/wallet.c:2294 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:2338 +#: wallet/wallet.c:2347 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:2399 +#: wallet/wallet.c:2408 msgid "UPDATE channel_htlcs SET hstate=?, payment_key=?, malformed_onion=?, failuremsg=?, localfailmsg=?, we_filled=? WHERE id=?" msgstr "" -#: wallet/wallet.c:2616 +#: wallet/wallet.c:2625 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:2663 +#: wallet/wallet.c:2672 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:2794 +#: wallet/wallet.c:2803 msgid "SELECT channel_id, direction, cltv_expiry, channel_htlc_id, payment_hash FROM channel_htlcs WHERE channel_id = ?;" msgstr "" -#: wallet/wallet.c:2828 +#: wallet/wallet.c:2837 msgid "DELETE FROM channel_htlcs WHERE direction = ? AND origin_htlc = ? AND payment_hash = ? AND partid = ?;" msgstr "" -#: wallet/wallet.c:2881 +#: wallet/wallet.c:2890 msgid "SELECT status FROM payments WHERE payment_hash=? AND partid = ?;" msgstr "" -#: wallet/wallet.c:2899 +#: wallet/wallet.c:2908 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:2988 +#: wallet/wallet.c:2997 msgid "DELETE FROM payments WHERE payment_hash = ? AND partid = ?" msgstr "" -#: wallet/wallet.c:3002 +#: wallet/wallet.c:3011 msgid "DELETE FROM payments WHERE payment_hash = ?" msgstr "" -#: wallet/wallet.c:3103 +#: wallet/wallet.c:3112 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:3153 +#: wallet/wallet.c:3162 msgid "UPDATE payments SET status=? WHERE payment_hash=? AND partid=?" msgstr "" -#: wallet/wallet.c:3163 +#: wallet/wallet.c:3172 msgid "UPDATE payments SET payment_preimage=? WHERE payment_hash=? AND partid=?" msgstr "" -#: wallet/wallet.c:3173 +#: wallet/wallet.c:3182 msgid "UPDATE payments SET path_secrets = NULL , route_nodes = NULL , route_channels = NULL WHERE payment_hash = ? AND partid = ?;" msgstr "" -#: wallet/wallet.c:3205 +#: wallet/wallet.c:3214 msgid "SELECT failonionreply, faildestperm, failindex, failcode, failnode, failchannel, failupdate, faildetail, faildirection FROM payments WHERE payment_hash=? AND partid=?;" msgstr "" -#: wallet/wallet.c:3272 +#: wallet/wallet.c:3281 msgid "UPDATE payments SET failonionreply=? , faildestperm=? , failindex=? , failcode=? , failnode=? , failchannel=? , failupdate=? , faildetail=? , faildirection=? WHERE payment_hash=? AND partid=?;" msgstr "" -#: wallet/wallet.c:3331 +#: wallet/wallet.c:3340 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:3354 +#: wallet/wallet.c:3363 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:3405 +#: wallet/wallet.c:3414 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:3450 +#: wallet/wallet.c:3459 msgid "DELETE FROM htlc_sigs WHERE channelid = ?" msgstr "" -#: wallet/wallet.c:3457 +#: wallet/wallet.c:3466 msgid "INSERT INTO htlc_sigs (channelid, signature) VALUES (?, ?)" msgstr "" -#: wallet/wallet.c:3469 +#: wallet/wallet.c:3478 msgid "SELECT blobval FROM vars WHERE name='genesis_hash'" msgstr "" -#: wallet/wallet.c:3493 +#: wallet/wallet.c:3502 msgid "INSERT INTO vars (name, blobval) VALUES ('genesis_hash', ?);" msgstr "" -#: wallet/wallet.c:3511 +#: wallet/wallet.c:3520 msgid "SELECT txid, outnum FROM utxoset WHERE spendheight < ?" msgstr "" -#: wallet/wallet.c:3523 +#: wallet/wallet.c:3532 msgid "DELETE FROM utxoset WHERE spendheight < ?" msgstr "" -#: wallet/wallet.c:3531 wallet/wallet.c:3645 +#: wallet/wallet.c:3540 wallet/wallet.c:3654 msgid "INSERT INTO blocks (height, hash, prev_hash) VALUES (?, ?, ?);" msgstr "" -#: wallet/wallet.c:3550 +#: wallet/wallet.c:3559 msgid "DELETE FROM blocks WHERE hash = ?" msgstr "" -#: wallet/wallet.c:3556 +#: wallet/wallet.c:3565 msgid "SELECT * FROM blocks WHERE height >= ?;" msgstr "" -#: wallet/wallet.c:3565 +#: wallet/wallet.c:3574 msgid "DELETE FROM blocks WHERE height > ?" msgstr "" -#: wallet/wallet.c:3577 +#: wallet/wallet.c:3586 msgid "UPDATE outputs SET spend_height = ?, status = ? WHERE prev_out_tx = ? AND prev_out_index = ?" msgstr "" -#: wallet/wallet.c:3595 +#: wallet/wallet.c:3604 msgid "UPDATE utxoset SET spendheight = ? WHERE txid = ? AND outnum = ?" msgstr "" -#: wallet/wallet.c:3618 wallet/wallet.c:3656 +#: wallet/wallet.c:3627 wallet/wallet.c:3665 msgid "INSERT INTO utxoset ( txid, outnum, blockheight, spendheight, txindex, scriptpubkey, satoshis) VALUES(?, ?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:3682 +#: wallet/wallet.c:3691 msgid "SELECT height FROM blocks WHERE height = ?" msgstr "" -#: wallet/wallet.c:3695 +#: wallet/wallet.c:3704 msgid "SELECT txid, spendheight, scriptpubkey, satoshis FROM utxoset WHERE blockheight = ? AND txindex = ? AND outnum = ? AND spendheight IS NULL" msgstr "" -#: wallet/wallet.c:3737 +#: wallet/wallet.c:3746 msgid "SELECT blockheight, txindex, outnum FROM utxoset WHERE spendheight = ?" msgstr "" -#: wallet/wallet.c:3768 wallet/wallet.c:3928 +#: wallet/wallet.c:3777 wallet/wallet.c:3937 msgid "SELECT blockheight FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3778 +#: wallet/wallet.c:3787 msgid "INSERT INTO transactions ( id, blockheight, txindex, rawtx) VALUES (?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:3799 +#: wallet/wallet.c:3808 msgid "UPDATE transactions SET blockheight = ?, txindex = ? WHERE id = ?" msgstr "" -#: wallet/wallet.c:3816 +#: wallet/wallet.c:3825 msgid "INSERT INTO transaction_annotations (txid, idx, location, type, channel) VALUES (?, ?, ?, ?, ?) ON CONFLICT(txid,idx) DO NOTHING;" msgstr "" -#: wallet/wallet.c:3848 +#: wallet/wallet.c:3857 msgid "SELECT type, channel_id FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3864 +#: wallet/wallet.c:3873 msgid "UPDATE transactions SET type = ?, channel_id = ? WHERE id = ?" msgstr "" -#: wallet/wallet.c:3883 +#: wallet/wallet.c:3892 msgid "SELECT type FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3906 +#: wallet/wallet.c:3915 msgid "SELECT rawtx FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3952 +#: wallet/wallet.c:3961 msgid "SELECT blockheight, txindex FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3980 +#: wallet/wallet.c:3989 msgid "SELECT id FROM transactions WHERE blockheight=?" msgstr "" -#: wallet/wallet.c:3999 +#: wallet/wallet.c:4008 msgid "INSERT INTO channeltxs ( channel_id, type, transaction_id, input_num, blockheight) VALUES (?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:4023 +#: wallet/wallet.c:4032 msgid "SELECT DISTINCT(channel_id) FROM channeltxs WHERE type = ?;" msgstr "" -#: wallet/wallet.c:4044 +#: wallet/wallet.c:4053 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:4089 +#: wallet/wallet.c:4098 msgid "UPDATE forwarded_payments SET in_msatoshi=?, out_msatoshi=?, state=?, resolved_time=?, failcode=? WHERE in_htlc_id=?" msgstr "" -#: wallet/wallet.c:4147 +#: wallet/wallet.c:4156 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:4206 +#: wallet/wallet.c:4215 msgid "SELECT CAST(COALESCE(SUM(in_msatoshi - out_msatoshi), 0) AS BIGINT)FROM forwarded_payments WHERE state = ?;" msgstr "" -#: wallet/wallet.c:4255 +#: wallet/wallet.c:4264 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:4377 +#: wallet/wallet.c:4386 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:4471 +#: wallet/wallet.c:4480 msgid "INSERT INTO penalty_bases ( channel_id, commitnum, txid, outnum, amount) VALUES (?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:4496 +#: wallet/wallet.c:4505 msgid "SELECT commitnum, txid, outnum, amount FROM penalty_bases WHERE channel_id = ?" msgstr "" -#: wallet/wallet.c:4520 +#: wallet/wallet.c:4529 msgid "DELETE FROM penalty_bases WHERE channel_id = ? AND commitnum = ?" msgstr "" -#: wallet/wallet.c:4538 +#: wallet/wallet.c:4547 msgid "SELECT 1 FROM offers WHERE offer_id = ?;" msgstr "" -#: wallet/wallet.c:4551 +#: wallet/wallet.c:4560 msgid "INSERT INTO offers ( offer_id, bolt12, label, status) VALUES (?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:4578 +#: wallet/wallet.c:4587 msgid "SELECT bolt12, label, status FROM offers WHERE offer_id = ?;" msgstr "" -#: wallet/wallet.c:4606 +#: wallet/wallet.c:4615 msgid "SELECT offer_id FROM offers;" msgstr "" -#: wallet/wallet.c:4632 +#: wallet/wallet.c:4641 msgid "UPDATE offers SET status=? WHERE offer_id = ?;" msgstr "" -#: wallet/wallet.c:4643 +#: wallet/wallet.c:4652 msgid "UPDATE invoices SET state=? WHERE state=? AND local_offer_id = ?;" msgstr "" -#: wallet/wallet.c:4671 +#: wallet/wallet.c:4680 msgid "SELECT status FROM offers WHERE offer_id = ?;" msgstr "" @@ -1337,4 +1337,4 @@ msgstr "" #: wallet/test/run-wallet.c:1696 msgid "INSERT INTO channels (id) VALUES (1);" msgstr "" -# SHA256STAMP:c1ab278c0d0e353eaf62f3c02566a42bdc65443fae40eebe182c11f3fd51abef +# SHA256STAMP:c8431455ff375f6a6d9225082d2529a06e01ebf508690765721740d5af851987 diff --git a/wallet/wallet.c b/wallet/wallet.c index e23f3d32aebb..348460f02ef2 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -516,7 +516,8 @@ static bool excluded(const struct utxo **excludes, return false; } -static bool deep_enough(u32 maxheight, const struct utxo *utxo) +static bool deep_enough(u32 maxheight, const struct utxo *utxo, + u32 current_blockheight) { /* If we require confirmations check that we have a * confirmation height and that it is below the required @@ -525,6 +526,13 @@ static bool deep_enough(u32 maxheight, const struct utxo *utxo) return true; if (!utxo->blockheight) return false; + /* Check that CSV-lock is now free! */ + if (utxo->close_info) { + u32 csv_free = *utxo->blockheight + utxo->close_info->csv; + assert(csv_free > *utxo->blockheight); + if (csv_free < current_blockheight) + return false; + } return *utxo->blockheight <= maxheight; } @@ -572,7 +580,8 @@ struct utxo *wallet_find_utxo(const tal_t *ctx, struct wallet *w, utxo = NULL; while (!utxo && db_step(stmt)) { utxo = wallet_stmt2output(ctx, stmt); - if (excluded(excludes, utxo) || !deep_enough(maxheight, utxo)) + if (excluded(excludes, utxo) + || !deep_enough(maxheight, utxo, current_blockheight)) utxo = tal_free(utxo); } From 18745a53054d1151912078dd017c70fd6f0f7e6c Mon Sep 17 00:00:00 2001 From: niftynei Date: Fri, 2 Jul 2021 15:21:54 -0500 Subject: [PATCH 39/56] channeld: don't forget channels that we've put funds into Typically we forget a channel if 2016 blocks have passed and the funding transaction hasn't been mined yet, however we SHOULD NOT forget these channels if we've got funds in them! --- lightningd/channel_control.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index 36db119faa8d..44793eb40796 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -767,6 +767,10 @@ is_fundee_should_forget(struct lightningd *ld, if (block_height - channel->first_blocknum < max_funding_unconfirmed) return false; + /* If we've got funds in the channel, don't forget it */ + if (!amount_sat_zero(channel->our_funds)) + return false; + /* Ah forget it! */ return true; } From b0e4e7fd7b617a4beba8c41f3589a8c9833040e5 Mon Sep 17 00:00:00 2001 From: niftynei Date: Fri, 2 Jul 2021 15:25:40 -0500 Subject: [PATCH 40/56] channel lease: fail leased channel if peer offline + blockheight behind If the channel is leased and our peer is too far behind, fail the channel. --- lightningd/channel_control.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index 44793eb40796..3940dab5a32b 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -75,12 +75,38 @@ static void try_update_blockheight(struct lightningd *ld, { u8 *msg; - /* We use the same heuristic for channel states as feerates */ - if (!channel_fees_can_change(channel)) + log_debug(channel->log, "attempting update blockheight %s", + type_to_string(tmpctx, struct channel_id, &channel->cid)); + + /* If they're offline, check that we're not too far behind anyway */ + if (!channel->owner) { + if (channel->opener == REMOTE + && channel->lease_expiry > 0) { + u32 peer_height + = get_blockheight(channel->blockheight_states, + channel->opener, REMOTE); + + /* Lease no longer active, we don't (really) care */ + if (peer_height >= channel->lease_expiry) + return; + + assert(peer_height + 1008 > peer_height); + if (peer_height + 1008 < blockheight) + channel_fail_permanent(channel, + REASON_PROTOCOL, + "Offline peer is too" + " far behind," + " terminating leased" + " channel. Our current" + " %u, theirs %u", + blockheight, + peer_height); + } return; + } - /* Can't if no daemon listening. */ - if (!channel->owner) + /* If we're not opened/locked in yet, don't send update */ + if (!channel_fees_can_change(channel)) return; /* We don't update the blockheight for non-leased chans */ From 971041f9c0b78e045a041f7bf357f8df6da3c3ed Mon Sep 17 00:00:00 2001 From: niftynei Date: Fri, 2 Jul 2021 15:38:59 -0500 Subject: [PATCH 41/56] close: param to force-close a leased channel By default, we won't close a channel that we leased to a peer. You can override this with the `force_lease_closed` flag. Changelog-Added: JSON-RPC: close now has parameter to force close a leased channel (option_will_fund) --- channeld/channeld.c | 3 +++ contrib/pyln-client/pyln/client/lightning.py | 10 ++++++++-- doc/lightning-close.7 | 9 +++++++-- doc/lightning-close.7.md | 7 ++++++- lightningd/peer_control.c | 13 ++++++++++++- 5 files changed, 36 insertions(+), 6 deletions(-) diff --git a/channeld/channeld.c b/channeld/channeld.c index f385a72ce486..f14c0170ec6b 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -1979,6 +1979,9 @@ static void handle_peer_shutdown(struct peer *peer, const u8 *shutdown) peer_failed_warn(peer->pps, &peer->channel_id, "Bad shutdown %s", tal_hex(peer, shutdown)); + /* FIXME: We shouldn't let them initiate a shutdown while the + * channel is active (if we leased funds) */ + /* BOLT #2: * * - if both nodes advertised the `option_upfront_shutdown_script` diff --git a/contrib/pyln-client/pyln/client/lightning.py b/contrib/pyln-client/pyln/client/lightning.py index 63c919a4c467..756157b0f5ed 100644 --- a/contrib/pyln-client/pyln/client/lightning.py +++ b/contrib/pyln-client/pyln/client/lightning.py @@ -515,17 +515,23 @@ def check(self, command_to_check, **kwargs): payload.update({k: v for k, v in kwargs.items()}) return self.call("check", payload) - def close(self, peer_id, unilateraltimeout=None, destination=None, fee_negotiation_step=None): + def close(self, peer_id, unilateraltimeout=None, destination=None, fee_negotiation_step=None, force_lease_closed=False): """ Close the channel with peer {id}, forcing a unilateral close after {unilateraltimeout} seconds if non-zero, and the to-local output will be sent to {destination}. + + If channel funds have been leased to the peer and the + lease has not yet expired, you can force a close with + {force_lease_closed}. Note that your funds will still be + locked until the lease expires. """ payload = { "id": peer_id, "unilateraltimeout": unilateraltimeout, "destination": destination, - "fee_negotiation_step": fee_negotiation_step + "fee_negotiation_step": fee_negotiation_step, + "force_lease_closed": force_lease_closed, } return self.call("close", payload) diff --git a/doc/lightning-close.7 b/doc/lightning-close.7 index c6313e41716a..4351ae8a69c1 100644 --- a/doc/lightning-close.7 +++ b/doc/lightning-close.7 @@ -3,7 +3,7 @@ lightning-close - Command for closing channels with direct peers .SH SYNOPSIS -\fBclose\fR \fIid\fR [\fIunilateraltimeout\fR] [\fIdestination\fR] [\fIfee_negotiation_step\fR] [\fIwrong_funding\\\fR] +\fBclose\fR \fIid\fR [\fIunilateraltimeout\fR] [\fIdestination\fR] [\fIfee_negotiation_step\fR] [\fIwrong_funding\fR] [\fIforce_lease_closed\fR] .SH DESCRIPTION @@ -64,6 +64,11 @@ allowed if this peer opened the channel and the channel is unused: it can rescue openings which have been manually miscreated\. +\fIforce_lease_closed\fR if the channel has funds leased to the peer +(option_will_fund), we prevent initiation of a mutual close +unless this flag is passed in\. Defaults to false\. + + The peer needs to be live and connected in order to negotiate a mutual close\. The default of unilaterally closing after 48 hours is usually a reasonable indication that you can no longer contact the peer\. @@ -120,4 +125,4 @@ ZmnSCPxj \fI is mainly responsible\. Main web site: \fIhttps://github.com/ElementsProject/lightning\fR -\" SHA256STAMP:507a9ca707e244eef65c5e16daa5a4d7ba8f59e93e988d252f7e854ae9f44781 +\" SHA256STAMP:c39f743723b34ad987d72c19a71d304c6bdd22db1fe78a137b38c9b20ddf5fad diff --git a/doc/lightning-close.7.md b/doc/lightning-close.7.md index 306598ca7a85..3e16d9449fe7 100644 --- a/doc/lightning-close.7.md +++ b/doc/lightning-close.7.md @@ -4,7 +4,7 @@ lightning-close -- Command for closing channels with direct peers SYNOPSIS -------- -**close** *id* \[*unilateraltimeout*\] \[*destination*\] \[*fee_negotiation_step*\] \[*wrong_funding\*] +**close** *id* \[*unilateraltimeout*\] \[*destination*\] \[*fee_negotiation_step*\] \[*wrong_funding*\] \[*force_lease_closed*\] DESCRIPTION ----------- @@ -53,6 +53,11 @@ shutdown transaction will spend this output instead. This is only allowed if this peer opened the channel and the channel is unused: it can rescue openings which have been manually miscreated. +*force_lease_closed* if the channel has funds leased to the peer +(option_will_fund), we prevent initiation of a mutual close +unless this flag is passed in. Defaults to false. + + The peer needs to be live and connected in order to negotiate a mutual close. The default of unilaterally closing after 48 hours is usually a reasonable indication that you can no longer contact the peer. diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 7aa8cdd9c5c7..ac738274801b 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -1663,7 +1663,7 @@ static struct command_result *json_close(struct command *cmd, struct channel *channel COMPILER_WANTS_INIT("gcc 7.3.0 fails, 8.3 OK"); unsigned int *timeout; const u8 *close_to_script = NULL; - bool close_script_set, wrong_funding_changed; + bool close_script_set, wrong_funding_changed, *force_lease_close; const char *fee_negotiation_step_str; struct bitcoin_outpoint *wrong_funding; char* end; @@ -1676,6 +1676,8 @@ static struct command_result *json_close(struct command *cmd, p_opt("fee_negotiation_step", param_string, &fee_negotiation_step_str), p_opt("wrong_funding", param_outpoint, &wrong_funding), + p_opt_def("force_lease_closed", param_bool, + &force_lease_close, false), NULL)) return command_param_failed(); @@ -1705,6 +1707,15 @@ static struct command_result *json_close(struct command *cmd, "Peer has no active channel"); } + if (!*force_lease_close && channel->opener != LOCAL + && get_block_height(cmd->ld->topology) < channel->lease_expiry) + return command_fail(cmd, LIGHTNINGD, + "Peer leased this channel from us, we" + " shouldn't close until lease has expired" + " (lease expires block %u," + " current block %u)", + channel->lease_expiry, + get_block_height(cmd->ld->topology)); /* If we've set a local shutdown script for this peer, and it's not the * default upfront script, try to close to a different channel. From 5aa490fda0ab71f870066b259a1621cdf289da2b Mon Sep 17 00:00:00 2001 From: niftynei Date: Fri, 2 Jul 2021 15:54:03 -0500 Subject: [PATCH 42/56] channel lease: update the blockheight on reconnect, also We need to update the peer wrt our blockheight on reconnect --- channeld/channeld.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/channeld/channeld.c b/channeld/channeld.c index f14c0170ec6b..0b9bb2863ba6 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -2350,9 +2350,12 @@ static void resend_commitment(struct peer *peer, struct changed_htlc *last) const struct htlc **htlc_map; struct wally_tx_output *direct_outputs[NUM_SIDES]; - status_debug("Retransmitting commitment, feerate LOCAL=%u REMOTE=%u", + status_debug("Retransmitting commitment, feerate LOCAL=%u REMOTE=%u," + " blockheight LOCAL=%u REMOTE=%u", channel_feerate(peer->channel, LOCAL), - channel_feerate(peer->channel, REMOTE)); + channel_feerate(peer->channel, REMOTE), + channel_blockheight(peer->channel, LOCAL), + channel_blockheight(peer->channel, REMOTE)); /* Note that HTLCs must be *added* in order. Simplest thing to do * is to sort them all into ascending ID order here (we could do @@ -2428,11 +2431,15 @@ static void resend_commitment(struct peer *peer, struct changed_htlc *last) } } - /* Make sure they have the correct fee. */ + /* Make sure they have the correct fee and blockheight. */ if (peer->channel->opener == LOCAL) { msg = towire_update_fee(NULL, &peer->channel_id, channel_feerate(peer->channel, REMOTE)); sync_crypto_write(peer->pps, take(msg)); + + msg = towire_update_blockheight(NULL, &peer->channel_id, + channel_blockheight(peer->channel, REMOTE)); + sync_crypto_write(peer->pps, take(msg)); } /* Re-send the commitment_signed itself. */ From 34e9ee950da483a9eae936e929bee059ac55067a Mon Sep 17 00:00:00 2001 From: niftynei Date: Fri, 2 Jul 2021 16:00:17 -0500 Subject: [PATCH 43/56] lease rates: helpers for parsing, serializing + equating lease_rates We're gonna need them --- common/json_tok.c | 16 +++++++++ common/json_tok.h | 9 ++++++ common/lease_rates.c | 61 +++++++++++++++++++++++++++++++++++ common/lease_rates.h | 14 ++++++++ common/test/Makefile | 5 +++ common/test/run-json.c | 3 -- common/test/run-lease_rates.c | 6 ++++ gossipd/test/Makefile | 1 + plugins/Makefile | 3 ++ 9 files changed, 115 insertions(+), 3 deletions(-) diff --git a/common/json_tok.c b/common/json_tok.c index e30dfc35bfb4..ca9e9cc44cb6 100644 --- a/common/json_tok.c +++ b/common/json_tok.c @@ -542,3 +542,19 @@ struct command_result *param_outpoint_arr(struct command *cmd, } return NULL; } + +struct command_result *param_lease_hex(struct command *cmd, + const char *name, + const char *buffer, + const jsmntok_t *tok, + struct lease_rates **rates) +{ + if (!lease_rates_fromhex(cmd, buffer + tok->start, + tok->end - tok->start, + rates)) + return command_fail(cmd, JSONRPC2_INVALID_PARAMS, + "Could not decode '%s' %.*s", + name, json_tok_full_len(tok), + json_tok_full(buffer, tok)); + return NULL; +} diff --git a/common/json_tok.h b/common/json_tok.h index 394b2d7c09a0..13343c952dd7 100644 --- a/common/json_tok.h +++ b/common/json_tok.h @@ -4,6 +4,7 @@ #include "config.h" #include #include +#include #include #include #include @@ -189,4 +190,12 @@ struct command_result *param_outpoint_arr(struct command *cmd, const char *buffer, const jsmntok_t *tok, struct bitcoin_outpoint **outpoints); +/** + * Parse a 'compact-lease' (serialized lease_rates) back into lease_rates + */ +struct command_result *param_lease_hex(struct command *cmd, + const char *name, + const char *buffer, + const jsmntok_t *tok, + struct lease_rates **rates); #endif /* LIGHTNING_COMMON_JSON_TOK_H */ diff --git a/common/lease_rates.c b/common/lease_rates.c index c58939c91f56..4ab08c9d2691 100644 --- a/common/lease_rates.c +++ b/common/lease_rates.c @@ -2,10 +2,29 @@ #include #include #include +#include #include #include +#include #include +/* FIXME: Is there a better way to do this ? */ +bool lease_rates_eq(struct lease_rates *l1, + struct lease_rates *l2) +{ + if (!l1 != !l2) + return false; + + if (!l1) + return true; + + return l1->funding_weight == l2->funding_weight + && l1->channel_fee_max_base_msat == l2->channel_fee_max_base_msat + && l1->channel_fee_max_proportional_thousandths == l2->channel_fee_max_proportional_thousandths + && l1->lease_fee_base_sat == l2->lease_fee_base_sat + && l1->lease_fee_basis == l2->lease_fee_basis; +} + bool lease_rates_empty(struct lease_rates *rates) { if (!rates) @@ -93,3 +112,45 @@ bool lease_rates_set_lease_fee_sat(struct lease_rates *rates, rates->lease_fee_base_sat = amt.satoshis; /* Raw: conversion */ return rates->lease_fee_base_sat == amt.satoshis; /* Raw: comparsion */ } + +char *lease_rates_tohex(const tal_t *ctx, const struct lease_rates *rates) +{ + char *hex; + u8 *data = tal_arr(NULL, u8, 0); + towire_lease_rates(&data, rates); + hex = tal_hex(ctx, data); + tal_free(data); + return hex; +} + +bool lease_rates_fromhex(const tal_t *ctx, + const char *hexdata, size_t hexlen, + struct lease_rates **rates) +{ + const u8 *data = tal_hexdata(ctx, hexdata, hexlen); + size_t len = tal_bytelen(data); + + *rates = tal(ctx, struct lease_rates); + fromwire_lease_rates(&data, &len, *rates); + + if (data == NULL) { + tal_free(*rates); + return false; + } + + return true; +} + +char *lease_rates_fmt(const tal_t *ctx, const struct lease_rates *rates) +{ + return tal_fmt(ctx, "{channel_fee_max_base_msat=%u," + "channel_fee_max_ppt=%u," + "funding_weight=%u," + "lease_fee_base_sat=%u," + "lease_fee_basis=%u}", + rates->channel_fee_max_base_msat, + rates->channel_fee_max_proportional_thousandths, + rates->funding_weight, + rates->lease_fee_base_sat, + rates->lease_fee_basis); +} diff --git a/common/lease_rates.h b/common/lease_rates.h index e72edb92d598..d6e8b5afbf1c 100644 --- a/common/lease_rates.h +++ b/common/lease_rates.h @@ -19,6 +19,9 @@ void lease_rates_get_commitment(struct pubkey *pubkey, u16 chan_fee_ppt, struct sha256 *sha); +bool lease_rates_eq(struct lease_rates *l1, + struct lease_rates *l2); + bool lease_rates_calc_fee(struct lease_rates *rates, struct amount_sat accept_funding_sats, struct amount_sat requested_sats, @@ -28,4 +31,15 @@ bool lease_rates_calc_fee(struct lease_rates *rates, WARN_UNUSED_RESULT bool lease_rates_set_chan_fee_base_msat(struct lease_rates *rates, struct amount_msat amt); WARN_UNUSED_RESULT bool lease_rates_set_lease_fee_sat(struct lease_rates *rates, struct amount_sat amt); + +/* Convert 'lease_rates' into a hexstring */ +char *lease_rates_tohex(const tal_t *ctx, const struct lease_rates *rates); + +/* Convert 'lease_rates' from a hexstring */ +bool lease_rates_fromhex(const tal_t *ctx, + const char *hexdata, size_t len, + struct lease_rates **rates); + +/* Format a string describing the passed in lease_rates */ +char *lease_rates_fmt(const tal_t *ctx, const struct lease_rates *rates); #endif /* LIGHTNING_COMMON_LEASE_RATES_H */ diff --git a/common/test/Makefile b/common/test/Makefile index 49be68ef49ba..00413f5aee0e 100644 --- a/common/test/Makefile +++ b/common/test/Makefile @@ -25,12 +25,17 @@ common/test/run-json: \ common/amount.o \ common/base32.o \ common/bigsize.o \ + common/channel_id.o \ common/json.o \ common/json_stream.o \ + common/lease_rates.o \ + common/node_id.o \ + common/pseudorand.o \ common/wireaddr.o \ common/type_to_string.o \ wire/fromwire.o \ wire/onion$(EXP)_wiregen.o \ + wire/peer$(EXP)_wiregen.o \ wire/towire.o common/test/run-route common/test/run-route-specific: \ diff --git a/common/test/run-json.c b/common/test/run-json.c index 599808f08f36..dae35b4028db 100644 --- a/common/test/run-json.c +++ b/common/test/run-json.c @@ -15,9 +15,6 @@ bool fromwire_tlv(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, const struct tlv_record_type *types UNNEEDED, size_t num_types UNNEEDED, void *record UNNEEDED, struct tlv_field **fields UNNEEDED) { fprintf(stderr, "fromwire_tlv called!\n"); abort(); } -/* Generated stub for node_id_from_hexstr */ -bool node_id_from_hexstr(const char *str UNNEEDED, size_t slen UNNEEDED, struct node_id *id UNNEEDED) -{ fprintf(stderr, "node_id_from_hexstr called!\n"); abort(); } /* Generated stub for tlv_fields_valid */ bool tlv_fields_valid(const struct tlv_field *fields UNNEEDED, size_t *err_index UNNEEDED) { fprintf(stderr, "tlv_fields_valid called!\n"); abort(); } diff --git a/common/test/run-lease_rates.c b/common/test/run-lease_rates.c index 8ba88af8e1b4..8e6d307408c6 100644 --- a/common/test/run-lease_rates.c +++ b/common/test/run-lease_rates.c @@ -18,6 +18,9 @@ bool fromwire_bool(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) /* Generated stub for fromwire_fail */ void *fromwire_fail(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_fail called!\n"); abort(); } +/* Generated stub for fromwire_lease_rates */ +void fromwire_lease_rates(const u8 **cursor UNNEEDED, size_t *plen UNNEEDED, struct lease_rates *lease_rates UNNEEDED) +{ fprintf(stderr, "fromwire_lease_rates called!\n"); abort(); } /* Generated stub for fromwire_secp256k1_ecdsa_signature */ void fromwire_secp256k1_ecdsa_signature(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, secp256k1_ecdsa_signature *signature UNNEEDED) @@ -50,6 +53,9 @@ void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED) /* Generated stub for towire_bool */ void towire_bool(u8 **pptr UNNEEDED, bool v UNNEEDED) { fprintf(stderr, "towire_bool called!\n"); abort(); } +/* Generated stub for towire_lease_rates */ +void towire_lease_rates(u8 **p UNNEEDED, const struct lease_rates *lease_rates UNNEEDED) +{ fprintf(stderr, "towire_lease_rates called!\n"); abort(); } /* Generated stub for towire_secp256k1_ecdsa_signature */ void towire_secp256k1_ecdsa_signature(u8 **pptr UNNEEDED, const secp256k1_ecdsa_signature *signature UNNEEDED) diff --git a/gossipd/test/Makefile b/gossipd/test/Makefile index b9f0949115d8..28aaed2ce3d3 100644 --- a/gossipd/test/Makefile +++ b/gossipd/test/Makefile @@ -14,6 +14,7 @@ GOSSIPD_TEST_COMMON_OBJS := \ common/node_id.o \ common/json.o \ common/json_helpers.o \ + common/lease_rates.o \ common/pseudorand.o \ common/setup.o \ common/type_to_string.o \ diff --git a/plugins/Makefile b/plugins/Makefile index e315a9fbbca7..3d2cf3cd3005 100644 --- a/plugins/Makefile +++ b/plugins/Makefile @@ -89,7 +89,9 @@ ALL_PROGRAMS += $(PLUGINS) PLUGIN_COMMON_OBJS := \ bitcoin/base58.o \ + bitcoin/block.o \ bitcoin/feerate.o \ + bitcoin/preimage.o \ bitcoin/privkey.o \ bitcoin/psbt.o \ bitcoin/pubkey.o \ @@ -128,6 +130,7 @@ PLUGIN_COMMON_OBJS := \ common/wireaddr.o \ wire/fromwire.o \ wire/onion$(EXP)_wiregen.o \ + wire/peer$(EXP)_wiregen.o \ wire/tlvstream.o \ wire/towire.o From 2d9ef33a51ba5f953cf0bc4677a7752842e02687 Mon Sep 17 00:00:00 2001 From: niftynei Date: Fri, 2 Jul 2021 16:19:47 -0500 Subject: [PATCH 44/56] channel leases: pass expected lease rates around in compat form We need to know what the lease we're expecting is. To do this we pass around the hex encoded portion of the wire format. We can use this passed in expected lease rates to confirm that the peer is, in fact, using the same rates as what we have currently. Changelog-Added: JSON-RPC: fundchannel, multifundchannel, and openchannel_init now accept a 'compact_lease' for any requested funds --- contrib/pyln-client/pyln/client/lightning.py | 3 +- doc/lightning-fundchannel.7 | 11 +++++-- doc/lightning-fundchannel.7.md | 9 ++++-- doc/lightning-multifundchannel.7 | 8 +++-- doc/lightning-multifundchannel.7.md | 7 +++-- doc/lightning-openchannel_init.7 | 11 +++++-- doc/lightning-openchannel_init.7.md | 8 +++-- lightningd/dual_open_control.c | 19 ++++++++++-- lightningd/gossip_control.c | 6 ++++ openingd/dualopend.c | 31 +++++++++++++++++++- openingd/dualopend_wire.csv | 4 +++ openingd/dualopend_wiregen.c | 28 ++++++++++++++---- openingd/dualopend_wiregen.h | 6 ++-- plugins/funder.c | 5 +++- plugins/spender/fundchannel.c | 11 ++++++- plugins/spender/multifundchannel.c | 11 +++++++ plugins/spender/multifundchannel.h | 3 ++ plugins/spender/openchannel.c | 5 +++- 18 files changed, 156 insertions(+), 30 deletions(-) diff --git a/contrib/pyln-client/pyln/client/lightning.py b/contrib/pyln-client/pyln/client/lightning.py index 756157b0f5ed..d89c4696b02b 100644 --- a/contrib/pyln-client/pyln/client/lightning.py +++ b/contrib/pyln-client/pyln/client/lightning.py @@ -699,7 +699,7 @@ def feerates(self, style, urgent=None, normal=None, slow=None): } return self.call("feerates", payload) - def fundchannel(self, node_id, amount, feerate=None, announce=True, minconf=None, utxos=None, push_msat=None, close_to=None, request_amt=None): + def fundchannel(self, node_id, amount, feerate=None, announce=True, minconf=None, utxos=None, push_msat=None, close_to=None, request_amt=None, compact_lease=None): """ Fund channel with {id} using {amount} satoshis with feerate of {feerate} (uses default feerate if unset). @@ -723,6 +723,7 @@ def fundchannel(self, node_id, amount, feerate=None, announce=True, minconf=None "push_msat": push_msat, "close_to": close_to, "request_amt": request_amt, + "compact_lease": compact_lease, } return self.call("fundchannel", payload) diff --git a/doc/lightning-fundchannel.7 b/doc/lightning-fundchannel.7 index 91cc2203ce59..11e8ca275062 100644 --- a/doc/lightning-fundchannel.7 +++ b/doc/lightning-fundchannel.7 @@ -4,7 +4,7 @@ lightning-fundchannel - Command for establishing a lightning channel .SH SYNOPSIS \fBfundchannel\fR \fIid\fR \fIamount\fR [\fIfeerate\fR] [\fIannounce\fR] [\fIminconf\fR] -[\fIutxos\fR] [\fIpush_msat\fR] [\fIclose_to\fR] +[\fIutxos\fR] [\fIpush_msat\fR] [\fIclose_to\fR] [\fIrequest_amt\fR] [\fIcompact_lease\fR] .SH DESCRIPTION @@ -74,7 +74,12 @@ Returns \fBclose_to\fR set to closing script iff is negotiated\. \fIrequest_amt\fR is an amount of liquidity you'd like to lease from the peer\. If peer supports \fBoption_will_fund\fR, indicates to them to include this -much liquidity into the channel\. +much liquidity into the channel\. Must also pass in \fIcompact_lease\fR\. + + +\fIcompact_lease\fR is a compact represenation of the peer's expected +channel lease terms\. If the peer's terms don't match this set, we will +fail to open the channel\. This example shows how to use lightning-cli to open new channel with peer 03f\.\.\.fc1 from one whole utxo bcc1\.\.\.39c:0 @@ -134,4 +139,4 @@ channel parameters (funding limits, channel reserves, fees, etc\.)\. Main web site: \fIhttps://github.com/ElementsProject/lightning\fR -\" SHA256STAMP:f26c502b7c8da644606d64e08451732652b56e9182e16fa42fa2b3224fe5f9d4 +\" SHA256STAMP:4ca7f4d2c07416d6039999a9e1b28a58125d25beb385df543b6ec14974920779 diff --git a/doc/lightning-fundchannel.7.md b/doc/lightning-fundchannel.7.md index d8446e6322b7..a0c305d1f8e8 100644 --- a/doc/lightning-fundchannel.7.md +++ b/doc/lightning-fundchannel.7.md @@ -5,7 +5,7 @@ SYNOPSIS -------- **fundchannel** *id* *amount* \[*feerate*\] \[*announce*\] \[*minconf*\] -\[*utxos*\] \[*push_msat*\] \[*close_to*\] +\[*utxos*\] \[*push_msat*\] \[*close_to*\] \[*request_amt*\] \[*compact_lease*\] DESCRIPTION ----------- @@ -66,7 +66,12 @@ Returns `close_to` set to closing script iff is negotiated. *request_amt* is an amount of liquidity you'd like to lease from the peer. If peer supports `option_will_fund`, indicates to them to include this -much liquidity into the channel. +much liquidity into the channel. Must also pass in *compact_lease*. + +*compact_lease* is a compact represenation of the peer's expected +channel lease terms. If the peer's terms don't match this set, we will +fail to open the channel. + This example shows how to use lightning-cli to open new channel with peer 03f...fc1 from one whole utxo bcc1...39c:0 diff --git a/doc/lightning-multifundchannel.7 b/doc/lightning-multifundchannel.7 index 72289b042e44..717a75bd25b6 100644 --- a/doc/lightning-multifundchannel.7 +++ b/doc/lightning-multifundchannel.7 @@ -61,7 +61,11 @@ closing script iff is negotiated\. .IP \[bu] \fIrequest_amt\fR is the amount of liquidity you'd like to lease from peer\. If peer supports \fBoption_will_fund\fR, indicates to them to include this -much liquidity into the channel\. +much liquidity into the channel\. Must also pass in \fIcompact_lease\fR\. +.IP \[bu] +\fIcompact_lease\fR is a compact represenation of the peer's expected +channel lease terms\. If the peer's terms don't match this set, we will +fail to open the channel to this destination\. .RE @@ -181,4 +185,4 @@ ZmnSCPxj \fI is mainly responsible\. Main web site: \fIhttps://github.com/ElementsProject/lightning\fR -\" SHA256STAMP:d9a15c4547808d6e7fb1df0e9d1c4183c99ba2caa664c3b7bbb0dcfd15c4256c +\" SHA256STAMP:e8bb0dffab6f9d1b5345590c4d267a0778cde2a8fc0e84d1694e73a386da3de4 diff --git a/doc/lightning-multifundchannel.7.md b/doc/lightning-multifundchannel.7.md index eb95af563959..7e1ebe93b1c6 100644 --- a/doc/lightning-multifundchannel.7.md +++ b/doc/lightning-multifundchannel.7.md @@ -52,8 +52,11 @@ Readiness is indicated by **listpeers** reporting a *state* of `option_upfront_shutdown_script`. Returns `close_to` set to closing script iff is negotiated. * *request_amt* is the amount of liquidity you'd like to lease from peer. -If peer supports `option_will_fund`, indicates to them to include this -much liquidity into the channel. + If peer supports `option_will_fund`, indicates to them to include this + much liquidity into the channel. Must also pass in *compact_lease*. +* *compact_lease* is a compact represenation of the peer's expected + channel lease terms. If the peer's terms don't match this set, we will + fail to open the channel to this destination. There must be at least one entry in *destinations*; it cannot be an empty array. diff --git a/doc/lightning-openchannel_init.7 b/doc/lightning-openchannel_init.7 index d3cde84c77a7..f6206bf82a50 100644 --- a/doc/lightning-openchannel_init.7 +++ b/doc/lightning-openchannel_init.7 @@ -3,7 +3,7 @@ lightning-openchannel_init - Command to initiate a channel to a peer .SH SYNOPSIS -\fBopenchannel_init\fR \fIid\fR \fIamount\fR \fIinitalpsbt\fR [\fIcommitment_feerate\fR] [\fIfunding_feerate\fR] [\fIannounce\fR] [\fIclose_to\fR] [\fIrequest_amt\fR] +\fBopenchannel_init\fR \fIid\fR \fIamount\fR \fIinitalpsbt\fR [\fIcommitment_feerate\fR] [\fIfunding_feerate\fR] [\fIannounce\fR] [\fIclose_to\fR] [\fIrequest_amt\fR] [\fIcompact_lease\fR] .SH DESCRIPTION @@ -46,7 +46,12 @@ sent on close\. Only valid if both peers have negotiated \fIrequest_amt\fR is an amount of liquidity you'd like to lease from the peer\. If peer supports \fBoption_will_fund\fR, indicates to them to include this -much liquidity into the channel\. +much liquidity into the channel\. Must also pass in \fIcompact_lease\fR\. + + +\fIcompact_lease\fR is a compact represenation of the peer's expected +channel lease terms\. If the peer's terms don't match this set, we will +fail to open the channel\. .SH RETURN VALUE @@ -113,4 +118,4 @@ lightning-fundchannel_\fBcomplete\fR(7), \fBlightning-fundchannel\fR(7), Main web site: \fIhttps://github.com/ElementsProject/lightning\fR -\" SHA256STAMP:4a2cfb31a80ccc03c7dda75e52e8c67fa99aeae0dd6f6640e155f5f4e161d218 +\" SHA256STAMP:441d91dc7a69dd5b85a2b0f0a515aff984cd6882b03badf6318800439347e7c9 diff --git a/doc/lightning-openchannel_init.7.md b/doc/lightning-openchannel_init.7.md index d39bda276473..d2f172323cc1 100644 --- a/doc/lightning-openchannel_init.7.md +++ b/doc/lightning-openchannel_init.7.md @@ -4,7 +4,7 @@ lightning-openchannel\_init -- Command to initiate a channel to a peer SYNOPSIS -------- -**openchannel_init** *id* *amount* *initalpsbt* \[*commitment_feerate*\] \[*funding_feerate*\] \[*announce*\] \[*close_to*\] \[*request_amt*\] +**openchannel_init** *id* *amount* *initalpsbt* \[*commitment_feerate*\] \[*funding_feerate*\] \[*announce*\] \[*close_to*\] \[*request_amt*\] \[*compact_lease*\] DESCRIPTION ----------- @@ -40,7 +40,11 @@ sent on close. Only valid if both peers have negotiated *request_amt* is an amount of liquidity you'd like to lease from the peer. If peer supports `option_will_fund`, indicates to them to include this -much liquidity into the channel. +much liquidity into the channel. Must also pass in *compact_lease*. + +*compact_lease* is a compact represenation of the peer's expected +channel lease terms. If the peer's terms don't match this set, we will +fail to open the channel. RETURN VALUE diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index ab653e1a2ad3..29aa59c2da2e 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -1617,8 +1617,12 @@ static void handle_dry_run_finished(struct subd *dualopend, const u8 *msg) json_add_amount_sat_only(response, "our_funding_msat", our_funding); json_add_amount_sat_only(response, "their_funding_msat", their_funding); - if (rates) + if (rates) { json_add_lease_rates(response, rates); + /* As a convenience, add a hexstring version of this data */ + json_add_string(response, "compact_lease", + lease_rates_tohex(tmpctx, rates)); + } was_pending(command_success(cmd, response)); } @@ -2578,7 +2582,8 @@ static struct command_result *json_queryrates(struct command *cmd, channel->channel_flags, *request_amt, get_block_height(cmd->ld->topology), - true); + true, + NULL); subd_send_msg(channel->owner, take(msg)); return command_still_pending(cmd); @@ -2600,6 +2605,7 @@ static struct command_result *json_openchannel_init(struct command *cmd, struct wally_psbt *psbt; const u8 *our_upfront_shutdown_script; struct open_attempt *oa; + struct lease_rates *rates; struct command_result *res; u8 *msg; @@ -2612,9 +2618,15 @@ static struct command_result *json_openchannel_init(struct command *cmd, p_opt_def("announce", param_bool, &announce_channel, true), p_opt("close_to", param_bitcoin_address, &our_upfront_shutdown_script), p_opt_def("request_amt", param_sat, &request_amt, AMOUNT_SAT(0)), + p_opt("compact_lease", param_lease_hex, &rates), NULL)) return command_param_failed(); + /* Gotta expect some rates ! */ + if (!amount_sat_zero(*request_amt) && !rates) + return command_fail(cmd, JSONRPC2_INVALID_PARAMS, + "Must pass in 'compact_lease' if requesting" + " funds from peer"); psbt_val = AMOUNT_SAT(0); for (size_t i = 0; i < psbt->num_inputs; i++) { struct amount_sat in_amt = psbt_input_get_amount(psbt, i); @@ -2735,7 +2747,8 @@ static struct command_result *json_openchannel_init(struct command *cmd, channel->channel_flags, *request_amt, get_block_height(cmd->ld->topology), - false); + false, + rates); subd_send_msg(channel->owner, take(msg)); return command_still_pending(cmd); diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index ac97d345160d..7fa2b62a51a1 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -280,6 +281,11 @@ static void json_getnodes_reply(struct subd *gossip UNUSED, const u8 *reply, if (nodes[i]->rates) { json_object_start(response, "option_will_fund"); json_add_lease_rates(response, nodes[i]->rates); + /* As a convenience, add a hexstring version + * of this info */ + json_add_string(response, "compact_lease", + lease_rates_tohex(tmpctx, + nodes[i]->rates)); json_object_end(response); } json_object_end(response); diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 0e6dfc950777..ebb9ee8817c0 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -2576,6 +2576,7 @@ static void opener_start(struct state *state, u8 *msg) char *err_reason; struct amount_sat total, requested_sats, lease_fee; bool dry_run; + struct lease_rates *expected_rates; struct tx_state *tx_state = state->tx_state; if (!fromwire_dualopend_opener_init(state, msg, @@ -2587,7 +2588,8 @@ static void opener_start(struct state *state, u8 *msg) &state->channel_flags, &requested_sats, &tx_state->blockheight, - &dry_run)) + &dry_run, + &expected_rates)) master_badmsg(WIRE_DUALOPEND_OPENER_INIT, msg); state->our_role = TX_INITIATOR; @@ -2726,6 +2728,23 @@ static void opener_start(struct state *state, u8 *msg) open_err_warn(state, "%s", "Abort requested"); } + /* If we've requested funds and they've failed to provide + * to lease us (or give them to us for free?!) then we fail. + * This isn't spec'd but it makes the UX predictable */ + if (open_tlv->request_funds + && amount_sat_less(tx_state->accepter_funding, requested_sats)) + negotiation_failed(state, + "We requested %s, which is more" + " than they've offered to provide" + " (%s)", + type_to_string(tmpctx, + struct amount_sat, + &requested_sats), + type_to_string(tmpctx, + struct amount_sat, + &tx_state->accepter_funding)); + + /* BOLT- #2: * The accepting node: ... * - if they decide to accept the offer: @@ -2735,6 +2754,16 @@ static void opener_start(struct state *state, u8 *msg) char *err_msg; struct lease_rates *rates = &a_tlv->will_fund->lease_rates; + if (!lease_rates_eq(rates, expected_rates)) + negotiation_failed(state, + "Expected lease rates (%s)," + " their returned lease rates (%s)", + lease_rates_fmt(tmpctx, + expected_rates), + lease_rates_fmt(tmpctx, + rates)); + + tx_state->lease_expiry = tx_state->blockheight + LEASE_RATE_DURATION; msg = towire_dualopend_validate_lease(NULL, diff --git a/openingd/dualopend_wire.csv b/openingd/dualopend_wire.csv index 9b1e88c577b1..5608b2e41eb2 100644 --- a/openingd/dualopend_wire.csv +++ b/openingd/dualopend_wire.csv @@ -96,6 +96,7 @@ msgdata,dualopend_got_offer_reply,accepter_funding,amount_sat, msgdata,dualopend_got_offer_reply,psbt,wally_psbt, msgdata,dualopend_got_offer_reply,shutdown_len,u16, msgdata,dualopend_got_offer_reply,our_shutdown_scriptpubkey,?u8,shutdown_len +# must go last because of embedded tu32 msgdata,dualopend_got_offer_reply,lease_rates,?lease_rates, # dualopend->master: they offered a RBF, should we continue? @@ -179,6 +180,8 @@ msgdata,dualopend_opener_init,channel_flags,u8, msgdata,dualopend_opener_init,requested_sats,amount_sat, msgdata,dualopend_opener_init,blockheight,u32, msgdata,dualopend_opener_init,dry_run,bool, +# must go last because embedded tu32 +msgdata,dualopend_opener_init,expected_rates,?lease_rates, # dualopend->master received tx_sigs from peer msgtype,dualopend_funding_sigs,7010 @@ -231,6 +234,7 @@ msgtype,dualopend_dry_run,7026 msgdata,dualopend_dry_run,channel_id,channel_id, msgdata,dualopend_dry_run,our_funding,amount_sat, msgdata,dualopend_dry_run,their_funding,amount_sat, +# must go last because of embedded tu32 msgdata,dualopend_dry_run,lease_rates,?lease_rates, # dualopend -> master: validate liqudity offer sig diff --git a/openingd/dualopend_wiregen.c b/openingd/dualopend_wiregen.c index bfc8d745669f..5ca2984cc69f 100644 --- a/openingd/dualopend_wiregen.c +++ b/openingd/dualopend_wiregen.c @@ -340,6 +340,7 @@ u8 *towire_dualopend_got_offer_reply(const tal_t *ctx, struct amount_sat accepte towire_wally_psbt(&p, psbt); towire_u16(&p, shutdown_len); towire_u8_array(&p, our_shutdown_scriptpubkey, shutdown_len); + /* must go last because of embedded tu32 */ if (!lease_rates) towire_bool(&p, false); else { @@ -364,7 +365,8 @@ bool fromwire_dualopend_got_offer_reply(const tal_t *ctx, const void *p, struct // 2nd case our_shutdown_scriptpubkey *our_shutdown_scriptpubkey = shutdown_len ? tal_arr(ctx, u8, shutdown_len) : NULL; fromwire_u8_array(&cursor, &plen, *our_shutdown_scriptpubkey, shutdown_len); - if (!fromwire_bool(&cursor, &plen)) + /* must go last because of embedded tu32 */ + if (!fromwire_bool(&cursor, &plen)) *lease_rates = NULL; else { *lease_rates = tal(ctx, struct lease_rates); @@ -667,7 +669,7 @@ bool fromwire_dualopend_fail(const tal_t *ctx, const void *p, wirestring **reaso /* WIRE: DUALOPEND_OPENER_INIT */ /* master->dualopend: hello */ -u8 *towire_dualopend_opener_init(const tal_t *ctx, const struct wally_psbt *psbt, struct amount_sat funding_amount, const u8 *local_shutdown_scriptpubkey, u32 feerate_per_kw, u32 feerate_per_kw_funding, u8 channel_flags, struct amount_sat requested_sats, u32 blockheight, bool dry_run) +u8 *towire_dualopend_opener_init(const tal_t *ctx, const struct wally_psbt *psbt, struct amount_sat funding_amount, const u8 *local_shutdown_scriptpubkey, u32 feerate_per_kw, u32 feerate_per_kw_funding, u8 channel_flags, struct amount_sat requested_sats, u32 blockheight, bool dry_run, const struct lease_rates *expected_rates) { u16 local_shutdown_len = tal_count(local_shutdown_scriptpubkey); u8 *p = tal_arr(ctx, u8, 0); @@ -683,10 +685,17 @@ u8 *towire_dualopend_opener_init(const tal_t *ctx, const struct wally_psbt *psbt towire_amount_sat(&p, requested_sats); towire_u32(&p, blockheight); towire_bool(&p, dry_run); + /* must go last because embedded tu32 */ + if (!expected_rates) + towire_bool(&p, false); + else { + towire_bool(&p, true); + towire_lease_rates(&p, expected_rates); + } return memcheck(p, tal_count(p)); } -bool fromwire_dualopend_opener_init(const tal_t *ctx, const void *p, struct wally_psbt **psbt, struct amount_sat *funding_amount, u8 **local_shutdown_scriptpubkey, u32 *feerate_per_kw, u32 *feerate_per_kw_funding, u8 *channel_flags, struct amount_sat *requested_sats, u32 *blockheight, bool *dry_run) +bool fromwire_dualopend_opener_init(const tal_t *ctx, const void *p, struct wally_psbt **psbt, struct amount_sat *funding_amount, u8 **local_shutdown_scriptpubkey, u32 *feerate_per_kw, u32 *feerate_per_kw_funding, u8 *channel_flags, struct amount_sat *requested_sats, u32 *blockheight, bool *dry_run, struct lease_rates **expected_rates) { u16 local_shutdown_len; @@ -707,6 +716,13 @@ bool fromwire_dualopend_opener_init(const tal_t *ctx, const void *p, struct wall *requested_sats = fromwire_amount_sat(&cursor, &plen); *blockheight = fromwire_u32(&cursor, &plen); *dry_run = fromwire_bool(&cursor, &plen); + /* must go last because embedded tu32 */ + if (!fromwire_bool(&cursor, &plen)) + *expected_rates = NULL; + else { + *expected_rates = tal(ctx, struct lease_rates); + fromwire_lease_rates(&cursor, &plen, *expected_rates); + } return cursor != NULL; } @@ -991,6 +1007,7 @@ u8 *towire_dualopend_dry_run(const tal_t *ctx, const struct channel_id *channel_ towire_channel_id(&p, channel_id); towire_amount_sat(&p, our_funding); towire_amount_sat(&p, their_funding); + /* must go last because of embedded tu32 */ if (!lease_rates) towire_bool(&p, false); else { @@ -1010,7 +1027,8 @@ bool fromwire_dualopend_dry_run(const tal_t *ctx, const void *p, struct channel_ fromwire_channel_id(&cursor, &plen, channel_id); *our_funding = fromwire_amount_sat(&cursor, &plen); *their_funding = fromwire_amount_sat(&cursor, &plen); - if (!fromwire_bool(&cursor, &plen)) + /* must go last because of embedded tu32 */ + if (!fromwire_bool(&cursor, &plen)) *lease_rates = NULL; else { *lease_rates = tal(ctx, struct lease_rates); @@ -1078,4 +1096,4 @@ bool fromwire_dualopend_validate_lease_reply(const tal_t *ctx, const void *p, wi } return cursor != NULL; } -// SHA256STAMP:8d6c88b060336c28b978fc1501bbb372d2d525c6a40585d6341157026b8dfd65 +// SHA256STAMP:b849d2454ff747b97adbf68a13675b91673d06f05b454a9e96744a2c4a12930f diff --git a/openingd/dualopend_wiregen.h b/openingd/dualopend_wiregen.h index d03753420e24..443ff8453b7e 100644 --- a/openingd/dualopend_wiregen.h +++ b/openingd/dualopend_wiregen.h @@ -159,8 +159,8 @@ bool fromwire_dualopend_fail(const tal_t *ctx, const void *p, wirestring **reaso /* WIRE: DUALOPEND_OPENER_INIT */ /* master->dualopend: hello */ -u8 *towire_dualopend_opener_init(const tal_t *ctx, const struct wally_psbt *psbt, struct amount_sat funding_amount, const u8 *local_shutdown_scriptpubkey, u32 feerate_per_kw, u32 feerate_per_kw_funding, u8 channel_flags, struct amount_sat requested_sats, u32 blockheight, bool dry_run); -bool fromwire_dualopend_opener_init(const tal_t *ctx, const void *p, struct wally_psbt **psbt, struct amount_sat *funding_amount, u8 **local_shutdown_scriptpubkey, u32 *feerate_per_kw, u32 *feerate_per_kw_funding, u8 *channel_flags, struct amount_sat *requested_sats, u32 *blockheight, bool *dry_run); +u8 *towire_dualopend_opener_init(const tal_t *ctx, const struct wally_psbt *psbt, struct amount_sat funding_amount, const u8 *local_shutdown_scriptpubkey, u32 feerate_per_kw, u32 feerate_per_kw_funding, u8 channel_flags, struct amount_sat requested_sats, u32 blockheight, bool dry_run, const struct lease_rates *expected_rates); +bool fromwire_dualopend_opener_init(const tal_t *ctx, const void *p, struct wally_psbt **psbt, struct amount_sat *funding_amount, u8 **local_shutdown_scriptpubkey, u32 *feerate_per_kw, u32 *feerate_per_kw_funding, u8 *channel_flags, struct amount_sat *requested_sats, u32 *blockheight, bool *dry_run, struct lease_rates **expected_rates); /* WIRE: DUALOPEND_FUNDING_SIGS */ /* dualopend->master received tx_sigs from peer */ @@ -237,4 +237,4 @@ bool fromwire_dualopend_validate_lease_reply(const tal_t *ctx, const void *p, wi #endif /* LIGHTNING_OPENINGD_DUALOPEND_WIREGEN_H */ -// SHA256STAMP:8d6c88b060336c28b978fc1501bbb372d2d525c6a40585d6341157026b8dfd65 +// SHA256STAMP:b849d2454ff747b97adbf68a13675b91673d06f05b454a9e96744a2c4a12930f diff --git a/plugins/funder.c b/plugins/funder.c index e2e5997cc774..b44fdb80ba45 100644 --- a/plugins/funder.c +++ b/plugins/funder.c @@ -761,8 +761,11 @@ static void json_add_policy(struct json_stream *stream, json_add_num(stream, "fuzz_percent", policy->fuzz_factor); json_add_num(stream, "fund_probability", policy->fund_probability); - if (policy->rates) + if (policy->rates) { json_add_lease_rates(stream, policy->rates); + json_add_string(stream, "compact_lease", + lease_rates_tohex(tmpctx, policy->rates)); + } } static struct command_result * diff --git a/plugins/spender/fundchannel.c b/plugins/spender/fundchannel.c index e4b75756dea8..1423b191c805 100644 --- a/plugins/spender/fundchannel.c +++ b/plugins/spender/fundchannel.c @@ -43,6 +43,7 @@ json_fundchannel(struct command *cmd, const jsmntok_t *push_msat; const jsmntok_t *close_to; const jsmntok_t *request_amt; + const jsmntok_t *compact_lease; struct out_req *req; @@ -56,9 +57,15 @@ json_fundchannel(struct command *cmd, p_opt("push_msat", param_tok, &push_msat), p_opt("close_to", param_tok, &close_to), p_opt("request_amt", param_tok, &request_amt), + p_opt("compact_lease", param_tok, &compact_lease), NULL)) return command_param_failed(); + if (request_amt && !compact_lease) + return command_fail(cmd, JSONRPC2_INVALID_PARAMS, + "Must pass in 'compact_lease' if requesting" + " funds from peer"); + req = jsonrpc_request_start(cmd->plugin, cmd, "multifundchannel", &fundchannel_get_result, &forward_error, NULL); @@ -73,8 +80,10 @@ json_fundchannel(struct command *cmd, json_add_tok(req->js, "push_msat", push_msat, buf); if (close_to) json_add_tok(req->js, "close_to", close_to, buf); - if (request_amt) + if (request_amt) { json_add_tok(req->js, "request_amt", request_amt, buf); + json_add_tok(req->js, "compact_lease", compact_lease, buf); + } json_object_end(req->js); json_array_end(req->js); if (feerate) diff --git a/plugins/spender/multifundchannel.c b/plugins/spender/multifundchannel.c index 6df6931b6f27..e2de184467ed 100644 --- a/plugins/spender/multifundchannel.c +++ b/plugins/spender/multifundchannel.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -16,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -1816,6 +1818,7 @@ param_destinations_array(struct command *cmd, const char *name, struct amount_sat *amount, *request_amt; bool *announce; struct amount_msat *push_msat; + struct lease_rates *rates; dest = &(*dests)[i]; @@ -1832,6 +1835,7 @@ param_destinations_array(struct command *cmd, const char *name, &dest->close_to_str), p_opt_def("request_amt", param_sat, &request_amt, AMOUNT_SAT(0)), + p_opt("compact_lease", param_lease_hex, &rates), NULL)) return command_param_failed(); @@ -1854,6 +1858,12 @@ param_destinations_array(struct command *cmd, const char *name, json_dest, "output would be dust"); + if (!amount_sat_zero(*request_amt) && !rates) + return command_fail_badparam(cmd, name, buffer, + json_dest, + "Must pass in 'compact_" + "lease' if requesting" + " funds from peer"); dest->index = i; dest->addrhint = addrhint; dest->their_features = NULL; @@ -1867,6 +1877,7 @@ param_destinations_array(struct command *cmd, const char *name, dest->updated_psbt = NULL; dest->protocol = FUND_CHANNEL; dest->request_amt = *request_amt; + dest->rates = tal_steal(*dests, rates); /* Only one destination can have "all" indicator. */ if (dest->all) { diff --git a/plugins/spender/multifundchannel.h b/plugins/spender/multifundchannel.h index 0a1614ce4fe7..e9cfe5d46633 100644 --- a/plugins/spender/multifundchannel.h +++ b/plugins/spender/multifundchannel.h @@ -146,6 +146,9 @@ struct multifundchannel_destination { /* amount to request peer to lease (OPEN_CHANNEL) */ struct amount_sat request_amt; + + /* Channel lease rates that we expect the peer to respond with */ + struct lease_rates *rates; }; diff --git a/plugins/spender/openchannel.c b/plugins/spender/openchannel.c index 9f274aad74df..22cbb171f086 100644 --- a/plugins/spender/openchannel.c +++ b/plugins/spender/openchannel.c @@ -1026,9 +1026,12 @@ openchannel_init_dest(struct multifundchannel_destination *dest) &dest->push_msat)); /* Request some sats from the peer! */ - if (amount_sat_greater(dest->request_amt, AMOUNT_SAT(0))) + if (!amount_sat_zero(dest->request_amt)) { json_add_string(req->js, "request_amt", fmt_amount_sat(tmpctx, dest->request_amt)); + json_add_string(req->js, "compact_lease", + lease_rates_tohex(tmpctx, dest->rates)); + } return send_outreq(cmd->plugin, req); } From 06307aeca820495ee1d12314e931b84e56be5e97 Mon Sep 17 00:00:00 2001 From: niftynei Date: Fri, 2 Jul 2021 16:38:04 -0500 Subject: [PATCH 45/56] channel leases: add expected lease fee to opening PSBT We need to parse the feerate string, so we can figure out what our weight fee will be for a leased channel, so we go get the feerate and use that to calculate what our expected lease fee will be for the requested amount. --- plugins/spender/multifundchannel.c | 76 ++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 3 deletions(-) diff --git a/plugins/spender/multifundchannel.c b/plugins/spender/multifundchannel.c index e2de184467ed..5cce683f0966 100644 --- a/plugins/spender/multifundchannel.c +++ b/plugins/spender/multifundchannel.c @@ -1376,9 +1376,8 @@ after_fundpsbt(struct command *cmd, } - static struct command_result * -perform_fundpsbt(struct multifundchannel_command *mfc) +perform_fundpsbt(struct multifundchannel_command *mfc, u32 feerate) { struct out_req *req; @@ -1425,11 +1424,34 @@ perform_fundpsbt(struct multifundchannel_command *mfc) else { struct amount_sat sum = AMOUNT_SAT(0); for (size_t i = 0; i < tal_count(mfc->destinations); ++i) { + struct amount_sat requested + = mfc->destinations[i].request_amt; + if (!amount_sat_add(&sum, sum, mfc->destinations[i].amount)) return mfc_fail(mfc, JSONRPC2_INVALID_PARAMS, "Overflow while summing " "destination values."); + /* Also add in any fees for requested amt! */ + if (!amount_sat_zero(requested)) { + struct amount_sat fee; + + /* Assume they send >= what we've + * requested (otherwise we error) */ + if (!lease_rates_calc_fee(mfc->destinations[i].rates, + requested, requested, + feerate, + &fee)) + return mfc_fail(mfc, JSONRPC2_INVALID_PARAMS, + "Overflow calculating" + " lease fee."); + + + if (!amount_sat_add(&sum, sum, fee)) + return mfc_fail(mfc, JSONRPC2_INVALID_PARAMS, + "Overflow while summing" + " lease fee"); + } } json_add_string(req->js, "satoshi", type_to_string(tmpctx, struct amount_sat, @@ -1467,6 +1489,54 @@ perform_fundpsbt(struct multifundchannel_command *mfc) return send_outreq(mfc->cmd->plugin, req); } +static struct command_result * +after_getfeerate(struct command *cmd, + const char *buf, + const jsmntok_t *result, + struct multifundchannel_command *mfc) +{ + const char *err; + u32 feerate; + + plugin_log(mfc->cmd->plugin, LOG_DBG, + "mfc %"PRIu64": 'parsefeerate' done", mfc->id); + + err = json_scan(tmpctx, buf, result, + "{perkw:%}", + JSON_SCAN(json_to_number, &feerate)); + if (err) + mfc_fail(mfc, JSONRPC2_INVALID_PARAMS, + "Unable to parse feerate %s: %*.s", + err, json_tok_full_len(result), + json_tok_full(buf, result)); + + return perform_fundpsbt(mfc, feerate); +} + +static struct command_result * +getfeerate(struct multifundchannel_command *mfc) +{ + struct out_req *req; + /* With the introduction of channel leases (option_will_fund), + * we need to include enough in the PSBT to cover our expected + * fees for the channel open. This requires that we know + * the feerate ahead of time, so that we can figure the + * expected lease fees, and add that to the funding amount. */ + req = jsonrpc_request_start(mfc->cmd->plugin, + mfc->cmd, + "parsefeerate", + &after_getfeerate, + &mfc_forward_error, + mfc); + + /* Internally, it defaults to 'opening', so we use that here */ + if (!mfc->feerate_str) + mfc->feerate_str = "opening"; + json_add_string(req->js, "feerate", mfc->feerate_str); + + return send_outreq(mfc->cmd->plugin, req); +} + /*---------------------------------------------------------------------------*/ /*~ First, connect to all the peers. @@ -1511,7 +1581,7 @@ after_multiconnect(struct multifundchannel_command *mfc) dest->error_message); } - return perform_fundpsbt(mfc); + return getfeerate(mfc); } static struct command_result * From e7a57407cd1950f02cef570519263b8436ebaae2 Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 6 Jul 2021 12:17:51 -0500 Subject: [PATCH 46/56] channel-lease: reject if we're not currently advertising liquidity If there's no plugin currently in place, we simply won't return any funding at all, in which case we'd expect them to handle however they want. (our implementation would fail the open, as we only accept opens that have at least as much as we've requested provided) --- openingd/dualopend.c | 1 - plugins/funder.c | 13 +++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/openingd/dualopend.c b/openingd/dualopend.c index ebb9ee8817c0..2b9e0870c933 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -2025,7 +2025,6 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) /* This is an `option_will_fund` request */ if (open_tlv->request_funds) { - /* FIXME: Do we support this? */ requested_amt = amount_sat(open_tlv->request_funds->requested_sats); tx_state->blockheight diff --git a/plugins/funder.c b/plugins/funder.c index b44fdb80ba45..9dbbba5a4bf5 100644 --- a/plugins/funder.c +++ b/plugins/funder.c @@ -577,6 +577,19 @@ json_openchannel2_call(struct command *cmd, return command_hook_success(cmd); } + /* If they've requested funds, but we're not actually + * supporting requested funds...*/ + if (!current_policy->rates && + !amount_sat_zero(info->requested_lease)) { + struct json_stream *res = jsonrpc_stream_success(cmd); + json_add_string(res, "result", "reject"); + json_add_string(res, "error_message", + "Peer requested funds but we're not advertising" + " liquidity right now"); + return command_finished(cmd, res); + } + + /* Check that their block height isn't too far behind */ if (!amount_sat_zero(info->requested_lease)) { u32 upper_bound, lower_bound; From b39164f3e0426bfd16fe8d8edde4e6a36c62a674 Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 6 Jul 2021 12:19:34 -0500 Subject: [PATCH 47/56] nit: better error messages on dualopend's check_balances failures Make it easier to figure out what the inputs were to check_balances on two failure cases --- openingd/dualopend.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 2b9e0870c933..55a24675fbbd 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -765,8 +765,19 @@ static char *check_balances(const tal_t *ctx, * - the peer's total input satoshis is less than their outputs */ /* We check both, why not? */ - if (!amount_sat_greater_eq(initiator_inputs, initiator_outs)) - return "initiator inputs less than outputs"; + if (!amount_sat_greater_eq(initiator_inputs, initiator_outs)) { + return tal_fmt(tmpctx, + "initiator inputs less than outputs (%s < %s)" + " (lease fee %s)", + type_to_string(tmpctx, struct amount_sat, + &initiator_inputs), + type_to_string(tmpctx, struct amount_sat, + &initiator_outs), + type_to_string(tmpctx, struct amount_sat, + &lease_fee)); + + + } /* BOLT-f53ca2301232db780843e894f55d95d512f297f9 #2: * The receiving node: ... @@ -779,7 +790,10 @@ static char *check_balances(const tal_t *ctx, */ if (!amount_sat_sub(&accepter_diff, accepter_inputs, accepter_outs)) { - return "accepter inputs less than outputs"; + return tal_fmt(tmpctx, "accepter inputs %s less than outputs %s (lease fee %s)", + type_to_string(tmpctx, struct amount_sat, &accepter_inputs), + type_to_string(tmpctx, struct amount_sat, &accepter_outs), + type_to_string(tmpctx, struct amount_sat, &lease_fee)); } if (!amount_sat_sub(&initiator_diff, initiator_inputs, From eeaf4361685e364b12d0e5daac0eff8deb67c663 Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 6 Jul 2021 12:21:43 -0500 Subject: [PATCH 48/56] channel-leases: add lease fee to accepter's funding earlier up We need the 'actual' accepter's funding for the reserve calculations, which includes the lease fee that the opener is paying them, so we calculate it before doing all that jazz. However, we MUST send the actual "on paper" (e.g. without lease fee) amount to the peer in accept_channel2, so we stash the original amount and send it. --- openingd/dualopend.c | 90 +++++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 43 deletions(-) diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 55a24675fbbd..e001e893a3f3 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -2002,7 +2002,7 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) struct channel_id cid, full_cid; char *err_reason; u8 *msg; - struct amount_sat total, requested_amt, lease_fee; + struct amount_sat total, requested_amt, lease_fee, our_accept; enum dualopend_wire msg_type; struct tx_state *tx_state = state->tx_state; @@ -2153,6 +2153,50 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) return; } + /* This we bump the accepter_funding iff there's a lease, + * so we stash this here so we tell our peer the right amount */ + our_accept = tx_state->accepter_funding; + + /* Add our fee to our amount now */ + if (tx_state->rates) { + tx_state->lease_expiry + = tx_state->blockheight + LEASE_RATE_DURATION; + + /* BOLT- #2: + * The lease fee is added to the accepter's balance + * in a channel, in addition to the `funding_satoshi` + * that they are contributing. The channel initiator + * must contribute enough funds to cover + * `open_channel2`.`funding_satoshis`, the lease fee, + * and their tx weight * `funding_feerate_perkw` / 1000. + */ + if (!lease_rates_calc_fee(tx_state->rates, + tx_state->accepter_funding, + requested_amt, + state->feerate_per_kw_funding, + &lease_fee)) + negotiation_failed(state, + "Unable to calculate lease fee"); + + /* Add it to the accepter's total */ + if (!amount_sat_add(&tx_state->accepter_funding, + tx_state->accepter_funding, lease_fee)) + + negotiation_failed(state, + "Unable to add accepter's funding" + " and channel lease fee (%s + %s)", + type_to_string(tmpctx, + struct amount_sat, + &tx_state->accepter_funding), + type_to_string(tmpctx, + struct amount_sat, + &lease_fee)); + + } else { + tx_state->lease_expiry = 0; + lease_fee = AMOUNT_SAT(0); + } + /* Check that total funding doesn't overflow */ if (!amount_sat_add(&total, tx_state->opener_funding, tx_state->accepter_funding)) @@ -2231,7 +2275,8 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) msg = towire_accept_channel2(tmpctx, &state->channel_id, - tx_state->accepter_funding, + /* Our amount w/o the lease fee */ + our_accept, tx_state->localconf.dust_limit, tx_state->localconf.max_htlc_value_in_flight, tx_state->localconf.htlc_minimum, @@ -2254,47 +2299,6 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) sync_crypto_write(state->pps, msg); peer_billboard(false, "channel open: accept sent, waiting for reply"); - /* Add our fee to our amount now */ - if (tx_state->rates) { - tx_state->lease_expiry - = tx_state->blockheight + LEASE_RATE_DURATION; - - /* BOLT- #2: - * The lease fee is added to the accepter's balance - * in a channel, in addition to the `funding_satoshi` - * that they are contributing. The channel initiator - * must contribute enough funds to cover - * `open_channel2`.`funding_satoshis`, the lease fee, - * and their tx weight * `funding_feerate_perkw` / 1000. - */ - if (!lease_rates_calc_fee(tx_state->rates, - tx_state->accepter_funding, - requested_amt, - state->feerate_per_kw_funding, - &lease_fee)) - negotiation_failed(state, - "Unable to calculate lease fee"); - - /* Add it to the accepter's total */ - if (!amount_sat_add(&tx_state->accepter_funding, - tx_state->accepter_funding, lease_fee)) { - - negotiation_failed(state, - "Unable to add accepter's funding" - " and channel lease fee (%s + %s)", - type_to_string(tmpctx, - struct amount_sat, - &tx_state->accepter_funding), - type_to_string(tmpctx, - struct amount_sat, - &lease_fee)); - return; - } - } else { - tx_state->lease_expiry = 0; - lease_fee = AMOUNT_SAT(0); - } - /* This is unused in this flow. We re-use * the wire method between accepter + opener, so we set it * to an invalid number, 1 (initiator sets; valid is even) */ From 83596b85c5d41091e2088327e01fe84333ed66c5 Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 6 Jul 2021 12:25:24 -0500 Subject: [PATCH 49/56] dualopend: hold onto open_tlv for longer than the tmpctx persists with channel leases, we use the open_tlv data after a round of talking to the peer (which clears out the tmpctx). It'll get cleaned up when this peer opens/fails. --- openingd/dualopend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openingd/dualopend.c b/openingd/dualopend.c index e001e893a3f3..0be387b5c408 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -2612,7 +2612,7 @@ static void opener_start(struct state *state, u8 *msg) state->our_role = TX_INITIATOR; tx_state->tx_locktime = tx_state->psbt->tx->locktime; tx_state->feerate_per_kw_funding = state->feerate_per_kw_funding; - open_tlv = tlv_opening_tlvs_new(tmpctx); + open_tlv = tlv_opening_tlvs_new(state); /* BOLT-* #2 * If the peer's revocation basepoint is unknown (e.g. From e34e62ee427d52c6ac917bfa8561640bd1bb35c5 Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 6 Jul 2021 12:27:06 -0500 Subject: [PATCH 50/56] lease-channels: tests for the test gods Check that channel leases work as expected for unilateral closes and cheats! --- tests/test_closing.py | 339 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 339 insertions(+) diff --git a/tests/test_closing.py b/tests/test_closing.py index cd95224c2036..58d413fbb0da 100644 --- a/tests/test_closing.py +++ b/tests/test_closing.py @@ -718,6 +718,345 @@ def test_penalty_outhtlc(node_factory, bitcoind, executor, chainparams): assert account_balance(l2, channel_id) == 0 +# check that the fee paid is correct +def calc_lease_fee(amt, feerate, rates): + fee = rates['lease_fee_base_msat'] + fee += amt * rates['lease_fee_basis'] // 10 + fee += rates['funding_weight'] * feerate + return fee + + +@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') +@pytest.mark.openchannel('v2') +@pytest.mark.slow_test +def test_channel_lease_falls_behind(node_factory, bitcoind): + ''' + If our peer falls too far behind/doesn't send us an update for + their blockheight, the lessor fails the channel + ''' + opts = [{'funder-policy': 'match', 'funder-policy-mod': 100, + 'lease-fee-base-msat': '100sat', 'lease-fee-basis': 100}, + {'funder-policy': 'match', 'funder-policy-mod': 100, + 'lease-fee-base-msat': '100sat', 'lease-fee-basis': 100}] + l1, l2, = node_factory.get_nodes(2, opts=opts) + amount = 500000 + feerate = 2000 + l1.fundwallet(20000000) + l2.fundwallet(20000000) + + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + rates = l1.rpc.queryrates(l2.info['id'], amount, amount) + l1.daemon.wait_for_log('disconnect') + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + # l1 leases a channel from l2 + l1.rpc.fundchannel(l2.info['id'], amount, request_amt=amount, + feerate='{}perkw'.format(feerate), + compact_lease=rates['compact_lease']) + + # sink the funding transaction + bitcoind.generate_block(1) + + # stop l1 + l1.stop() + + # advance blockchain 1008 blocks, the lessor should drop to chain + bitcoind.generate_block(1008) + sync_blockheight(bitcoind, [l2]) + + l2.daemon.wait_for_log('Offline peer is too far behind, terminating') + + +@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') +@pytest.mark.openchannel('v2') +@pytest.mark.slow_test +def test_channel_lease_closes(node_factory, bitcoind): + ''' + Check that channel leases work + + l1-l2: l1 leases funds from l2; l1 goes to chain unilaterally + l2-l3: l2 leases funds from l3; l3 goes to chain unilaterally + l4-l2: l4 leases funds from l2; mutual close at the end of the lease + ''' + + l1, l2, l3, l4 = node_factory.get_nodes(4, opts={'funder-policy': 'match', + 'funder-policy-mod': 100, + 'lease-fee-base-msat': '100sat', + 'lease-fee-basis': 100, + 'may_reconnect': True}) + feerate = 2000 + amount = 500000 + l1.fundwallet(20000000) + l2.fundwallet(20000000) + l3.fundwallet(20000000) + l4.fundwallet(20000000) + + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + rates = l1.rpc.queryrates(l2.info['id'], amount, amount) + l1.daemon.wait_for_log('disconnect') + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + # l1 leases a channel from l2 + l1.rpc.fundchannel(l2.info['id'], amount, request_amt=amount, + feerate='{}perkw'.format(feerate), + compact_lease=rates['compact_lease']) + + # free up some funds for l2 to fund a channel with l4 + bitcoind.generate_block(1, wait_for_mempool=1) + sync_blockheight(bitcoind, [l2]) + + # l4 leases a channel from l2 + l4.rpc.connect(l2.info['id'], 'localhost', l2.port) + # l4 leases a channel to l2 + l4.rpc.fundchannel(l2.info['id'], amount, request_amt=amount, + feerate='{}perkw'.format(feerate), + compact_lease=rates['compact_lease']) + + # l2 leases a channel from l3 + l2.rpc.connect(l3.info['id'], 'localhost', l3.port) + rates = l2.rpc.queryrates(l3.info['id'], amount, amount) + l3.daemon.wait_for_log('disconnect') + l2.rpc.connect(l3.info['id'], 'localhost', l3.port) + l2.rpc.fundchannel(l3.info['id'], amount, request_amt=amount, + feerate='{}perkw'.format(feerate), minconf=0, + compact_lease=rates['compact_lease']) + + est_fees = calc_lease_fee(amount, feerate, rates) + + # This should be the accepter's amount + fundings = only_one(only_one(l1.rpc.listpeers()['peers'])['channels'])['funding_msat'] + assert Millisatoshi(est_fees + amount * 1000) == Millisatoshi(fundings[l2.info['id']]) + + bitcoind.generate_block(6) + l1.daemon.wait_for_log('to CHANNELD_NORMAL') + l3.daemon.wait_for_log('to CHANNELD_NORMAL') + l4.daemon.wait_for_log('to CHANNELD_NORMAL') + + wait_for(lambda: [c['active'] for c in l1.rpc.listchannels(l1.get_channel_scid(l2))['channels']] == [True, True]) + wait_for(lambda: [c['active'] for c in l3.rpc.listchannels(l3.get_channel_scid(l2))['channels']] == [True, True]) + wait_for(lambda: [c['active'] for c in l4.rpc.listchannels(l4.get_channel_scid(l2))['channels']] == [True, True]) + + # send some payments, mine a block or two + inv = l2.rpc.invoice(10**4, '1', 'no_1') + l1.rpc.pay(inv['bolt11']) + inv = l2.rpc.invoice(10**4, '3', 'no_3') + l3.rpc.pay(inv['bolt11']) + inv = l2.rpc.invoice(10**4, '4', 'no_4') + l4.rpc.pay(inv['bolt11']) + + # l2 attempts to close a channel that it leased, should fail + with pytest.raises(RpcError, match=r'Peer leased this channel from us'): + l2.rpc.close(l4.get_channel_scid(l2)) + + bitcoind.generate_block(6) + sync_blockheight(bitcoind, [l1, l2, l3, l4]) + # make sure we're at the right place for the csv lock + l2.daemon.wait_for_log('Blockheight: SENT_ADD_ACK_COMMIT->RCVD_ADD_ACK_REVOCATION LOCAL now 112') + l2.stop() + + # unilateral close channels l1<->l2 & l3<->l2 + l1.rpc.close(l2.info['id'], 1) + l3.rpc.close(l2.info['id'], 1, force_lease_closed=True) + + # Wait til to_self_delay expires, l1 should claim to_local back + bitcoind.generate_block(10, wait_for_mempool=1) + l1.daemon.wait_for_log('Broadcasting OUR_DELAYED_RETURN_TO_WALLET') + bitcoind.generate_block(1, wait_for_mempool=1) + l1.daemon.wait_for_log('Resolved OUR_UNILATERAL/DELAYED_OUTPUT_TO_US by our proposal OUR_DELAYED_RETURN_TO_WALLET') + assert len(l1.rpc.listfunds()['outputs']) == 2 + + l2.start() + search_start = l2.daemon.logsearch_start + log = l2.daemon.wait_for_log('adding utxo to watch .* csv 40.*') + utxo1 = re.match('.* adding utxo to watch (.*), csv .*', log).group(1) + + l2.daemon.logsearch_start = search_start + log = l2.daemon.wait_for_log('adding utxo to watch .* csv 1') + utxo3 = re.match('.* adding utxo to watch (.*), csv 1', log).group(1) + + # we *shouldn't* be able to spend it, there's a lock on it + with pytest.raises(RpcError, match='UTXO .* is csv locked'): + l2.rpc.withdraw(l2.rpc.newaddr()['bech32'], "all", utxos=[utxo1]) + + # we *can* spend the 1csv lock one + l2.rpc.withdraw(l2.rpc.newaddr()['bech32'], "all", utxos=[utxo3]) + + # We need to give l4-l2 time to update their blockheights + bitcoind.generate_block(1000) + sync_blockheight(bitcoind, [l2, l3, l4]) + l4.daemon.wait_for_log('peer_out WIRE_UPDATE_BLOCKHEIGHT') + + bitcoind.generate_block(1000) + sync_blockheight(bitcoind, [l2, l3, l4]) + l4.daemon.wait_for_log('peer_out WIRE_UPDATE_BLOCKHEIGHT') + + bitcoind.generate_block(1000) + sync_blockheight(bitcoind, [l2, l3, l4]) + l4.daemon.wait_for_log('peer_out WIRE_UPDATE_BLOCKHEIGHT') + + bitcoind.generate_block(1000) + sync_blockheight(bitcoind, [l2, l3, l4]) + l4.daemon.wait_for_log('peer_out WIRE_UPDATE_BLOCKHEIGHT') + + bitcoind.generate_block(32) + sync_blockheight(bitcoind, [l2, l3, l4]) + l4.daemon.wait_for_log('peer_out WIRE_UPDATE_BLOCKHEIGHT') + + l2.rpc.withdraw(l2.rpc.newaddr()['bech32'], "all", utxos=[utxo1]) + + # l3 cleans up their to-self after their lease expires + assert l3.daemon.is_in_log('Broadcasting OUR_DELAYED_RETURN_TO_WALLET') + + # l2<->l4 mutual close should work + chan = l4.get_channel_scid(l2) + l2.rpc.connect(l4.info['id'], 'localhost', l4.port) + l4.rpc.close(chan) + l2.daemon.wait_for_log('State changed from CLOSINGD_SIGEXCHANGE to CLOSINGD_COMPLETE') + + +@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') +@pytest.mark.openchannel('v2') +@unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "Makes use of the sqlite3 db") +def test_channel_lease_lessor_cheat(node_factory, bitcoind, chainparams): + ''' + Check that lessee can recover funds if lessor cheats + ''' + opts = [{'funder-policy': 'match', 'funder-policy-mod': 100, + 'lease-fee-base-msat': '100sat', 'lease-fee-basis': 100, + 'may_reconnect': True, 'allow_warning': True}, + {'funder-policy': 'match', 'funder-policy-mod': 100, + 'lease-fee-base-msat': '100sat', 'lease-fee-basis': 100, + 'may_reconnect': True, 'allow_broken_log': True}] + l1, l2, = node_factory.get_nodes(2, opts=opts) + amount = 500000 + feerate = 2000 + l1.fundwallet(20000000) + l2.fundwallet(20000000) + + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + rates = l1.rpc.queryrates(l2.info['id'], amount, amount) + l1.daemon.wait_for_log('disconnect') + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + # l1 leases a channel from l2 + l1.rpc.fundchannel(l2.info['id'], amount, request_amt=amount, + feerate='{}perkw'.format(feerate), + compact_lease=rates['compact_lease']) + + bitcoind.generate_block(6) + l1.daemon.wait_for_log('to CHANNELD_NORMAL') + wait_for(lambda: [c['active'] for c in l1.rpc.listchannels(l1.get_channel_scid(l2))['channels']] == [True, True]) + wait_for(lambda: [c['active'] for c in l2.rpc.listchannels(l2.get_channel_scid(l1))['channels']] == [True, True]) + # send some payments, mine a block or two + inv = l2.rpc.invoice(10**4, '1', 'no_1') + l1.rpc.pay(inv['bolt11']) + + bitcoind.generate_block(1) + + # make database snapshot of l2 + l2.stop() + l2_db_path = os.path.join(l2.daemon.lightning_dir, chainparams['name'], 'lightningd.sqlite3') + l2_db_path_bak = os.path.join(l2.daemon.lightning_dir, chainparams['name'], 'lightningd.sqlite3.bak') + copyfile(l2_db_path, l2_db_path_bak) + l2.start() + l2.rpc.connect(l1.info['id'], 'localhost', l1.port) + sync_blockheight(bitcoind, [l2]) + + # push some money from l2->l1, so the commit counter advances + inv = l1.rpc.invoice(10**5, '2', 'no_2') + l2.rpc.pay(inv['bolt11']) + + # stop both nodes, roll back l2's database + l2.stop() + l1.stop() + copyfile(l2_db_path_bak, l2_db_path) + + # start l2 and force close channel with l1 while l1 is still offline + l2.start() + sync_blockheight(bitcoind, [l2]) + l2.rpc.close(l1.info['id'], 1, force_lease_closed=True) + bitcoind.generate_block(1, wait_for_mempool=1) + + l1.start() + sync_blockheight(bitcoind, [l1]) + l1.daemon.wait_for_logs(['Broadcasting OUR_PENALTY_TX', + ' Propose handling THEIR_REVOKED_UNILATERAL/DELAYED_CHEAT_OUTPUT_TO_THEM by OUR_PENALTY_TX']) + + bitcoind.generate_block(1, wait_for_mempool=1) + # l2 sees that l1 has spent their coins! + l2.daemon.wait_for_log('Unknown spend of OUR_UNILATERAL/DELAYED_OUTPUT_TO_US by') + + +@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') +@pytest.mark.openchannel('v2') +@unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "Makes use of the sqlite3 db") +def test_channel_lease_lessee_cheat(node_factory, bitcoind, chainparams): + ''' + Check that lessor can recover funds if lessee cheats + ''' + opts = [{'funder-policy': 'match', 'funder-policy-mod': 100, + 'lease-fee-base-msat': '100sat', 'lease-fee-basis': 100, + 'may_reconnect': True, 'allow_broken_log': True}, + {'funder-policy': 'match', 'funder-policy-mod': 100, + 'lease-fee-base-msat': '100sat', 'lease-fee-basis': 100, + 'may_reconnect': True}] + l1, l2, = node_factory.get_nodes(2, opts=opts) + amount = 500000 + feerate = 2000 + l1.fundwallet(20000000) + l2.fundwallet(20000000) + + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + rates = l1.rpc.queryrates(l2.info['id'], amount, amount) + l1.daemon.wait_for_log('disconnect') + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + # l1 leases a channel from l2 + l1.rpc.fundchannel(l2.info['id'], amount, request_amt=amount, + feerate='{}perkw'.format(feerate), + compact_lease=rates['compact_lease']) + + bitcoind.generate_block(6) + l1.daemon.wait_for_log('to CHANNELD_NORMAL') + wait_for(lambda: [c['active'] for c in l1.rpc.listchannels(l1.get_channel_scid(l2))['channels']] == [True, True]) + wait_for(lambda: [c['active'] for c in l2.rpc.listchannels(l2.get_channel_scid(l1))['channels']] == [True, True]) + # send some payments, mine a block or two + inv = l2.rpc.invoice(10**4, '1', 'no_1') + l1.rpc.pay(inv['bolt11']) + + bitcoind.generate_block(1) + + # make database snapshot of l1 + l1.stop() + l1_db_path = os.path.join(l1.daemon.lightning_dir, chainparams['name'], 'lightningd.sqlite3') + l1_db_path_bak = os.path.join(l1.daemon.lightning_dir, chainparams['name'], 'lightningd.sqlite3.bak') + copyfile(l1_db_path, l1_db_path_bak) + l1.start() + l1.rpc.connect(l1.info['id'], 'localhost', l1.port) + sync_blockheight(bitcoind, [l1]) + + # push some money from l2->l1, so the commit counter advances + inv = l1.rpc.invoice(10**5, '2', 'no_2') + l2.rpc.pay(inv['bolt11']) + + # stop both nodes, roll back l1's database + l1.stop() + l2.stop() + copyfile(l1_db_path_bak, l1_db_path) + + # start l1 and force close channel with l2 while l2 is still offline + l1.start() + sync_blockheight(bitcoind, [l1]) + l1.rpc.close(l2.info['id'], 1, force_lease_closed=True) + bitcoind.generate_block(1, wait_for_mempool=1) + + l2.start() + sync_blockheight(bitcoind, [l2]) + l2.daemon.wait_for_logs(['Broadcasting OUR_PENALTY_TX', + ' Propose handling THEIR_REVOKED_UNILATERAL/DELAYED_CHEAT_OUTPUT_TO_THEM by OUR_PENALTY_TX']) + + bitcoind.generate_block(1, wait_for_mempool=1) + # l2 sees that l1 has spent their coins! + l1.daemon.wait_for_logs(['Grinding for to_remote', + 'Unknown spend of OUR_UNILATERAL/DELAYED_OUTPUT_TO_US by']) + + @pytest.mark.developer("needs DEVELOPER=1") @unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "Makes use of the sqlite3 db") @pytest.mark.slow_test From fbadcf045887a58e4a1b03e85feeb0255c933a93 Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 6 Jul 2021 13:48:35 -0500 Subject: [PATCH 51/56] queryrates: make it dev-only Since we now use 'compact_lease' to gate an open (if the rates have changed, we fail), we no longer need to rely on query rates for figuring things out, so we make it dev-only. Changelog-Changed: JSON-API: queryrates is now developer only --- contrib/pyln-client/pyln/client/lightning.py | 4 +- contrib/startup_regtest.sh | 2 +- lightningd/dual_open_control.c | 207 ++++++++++--------- tests/test_closing.py | 14 +- tests/test_opening.py | 5 +- 5 files changed, 120 insertions(+), 112 deletions(-) diff --git a/contrib/pyln-client/pyln/client/lightning.py b/contrib/pyln-client/pyln/client/lightning.py index d89c4696b02b..6945134781f7 100644 --- a/contrib/pyln-client/pyln/client/lightning.py +++ b/contrib/pyln-client/pyln/client/lightning.py @@ -1018,7 +1018,7 @@ def pay(self, bolt11, msatoshi=None, label=None, riskfactor=None, } return self.call("pay", payload) - def queryrates(self, node_id, channel_amount, request_amt, commitment_feerate=None, funding_feerate=None): + def dev_queryrates(self, node_id, channel_amount, request_amt, commitment_feerate=None, funding_feerate=None): """Ask a peer how much they'd charge for a given liquidity amount """ payload = { "id": node_id, @@ -1027,7 +1027,7 @@ def queryrates(self, node_id, channel_amount, request_amt, commitment_feerate=No "commitment_feerate": commitment_feerate, "funding_feerate": funding_feerate, } - return self.call("queryrates", payload) + return self.call("dev-queryrates", payload) def openchannel_init(self, node_id, channel_amount, psbt, feerate=None, funding_feerate=None, announce=True, close_to=None, request_amt=None, *args, **kwargs): """Initiate an openchannel with a peer """ diff --git a/contrib/startup_regtest.sh b/contrib/startup_regtest.sh index 996e20fe9dfe..280ef85f95ad 100755 --- a/contrib/startup_regtest.sh +++ b/contrib/startup_regtest.sh @@ -109,7 +109,7 @@ start_nodes() { # Start the lightning nodes test -f "/tmp/l$i-$network/lightningd-$network.pid" || \ - "$LIGHTNINGD" "--lightning-dir=/tmp/l$i-$network" --daemon + "$LIGHTNINGD" "--lightning-dir=/tmp/l$i-$network" & # shellcheck disable=SC2139 disable=SC2086 alias l$i-cli="$LCLI --lightning-dir=/tmp/l$i-$network" # shellcheck disable=SC2139 disable=SC2086 diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index 29aa59c2da2e..14da1a34c854 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -2490,106 +2490,6 @@ static struct command_result *init_set_feerate(struct command *cmd, return NULL; } -static struct command_result *json_queryrates(struct command *cmd, - const char *buffer, - const jsmntok_t *obj UNNEEDED, - const jsmntok_t *params) -{ - struct node_id *id; - struct peer *peer; - struct channel *channel; - u32 *feerate_per_kw_funding; - u32 *feerate_per_kw; - struct amount_sat *amount, *request_amt; - struct wally_psbt *psbt; - struct open_attempt *oa; - u8 *msg; - struct command_result *res; - - if (!param(cmd, buffer, params, - p_req("id", param_node_id, &id), - p_req("amount", param_sat, &amount), - p_req("request_amt", param_sat, &request_amt), - p_opt("commitment_feerate", param_feerate, &feerate_per_kw), - p_opt("funding_feerate", param_feerate, &feerate_per_kw_funding), - NULL)) - return command_param_failed(); - - res = init_set_feerate(cmd, &feerate_per_kw, &feerate_per_kw_funding); - if (res) - return res; - - peer = peer_by_id(cmd->ld, id); - if (!peer) { - return command_fail(cmd, FUNDING_UNKNOWN_PEER, "Unknown peer"); - } - - /* We can't query rates for a peer we have a channel with */ - channel = peer_active_channel(peer); - if (channel) - return command_fail(cmd, LIGHTNINGD, "Peer in state %s," - " can't query peer's rates if already" - " have a channel", - channel_state_name(channel)); - - channel = peer_unsaved_channel(peer); - if (!channel || !channel->owner) - return command_fail(cmd, FUNDING_PEER_NOT_CONNECTED, - "Peer not connected"); - if (channel->open_attempt - || !list_empty(&channel->inflights)) - return command_fail(cmd, FUNDING_STATE_INVALID, - "Channel funding in-progress. %s", - channel_state_name(channel)); - - if (!feature_negotiated(cmd->ld->our_features, - peer->their_features, - OPT_DUAL_FUND)) { - return command_fail(cmd, FUNDING_V2_NOT_SUPPORTED, - "v2 openchannel not supported " - "by peer, can't query rates"); - } - - /* BOLT #2: - * - if both nodes advertised `option_support_large_channel`: - * - MAY set `funding_satoshis` greater than or equal to 2^24 satoshi. - * - otherwise: - * - MUST set `funding_satoshis` to less than 2^24 satoshi. - */ - if (!feature_negotiated(cmd->ld->our_features, - peer->their_features, OPT_LARGE_CHANNELS) - && amount_sat_greater(*amount, chainparams->max_funding)) - return command_fail(cmd, FUND_MAX_EXCEEDED, - "Amount exceeded %s", - type_to_string(tmpctx, struct amount_sat, - &chainparams->max_funding)); - - /* Get a new open_attempt going, keeps us from re-initing - * while looking */ - channel->opener = LOCAL; - channel->open_attempt = oa = new_channel_open_attempt(channel); - channel->channel_flags = OUR_CHANNEL_FLAGS; - oa->funding = *amount; - oa->cmd = cmd; - /* empty psbt to start */ - psbt = create_psbt(tmpctx, 0, 0, 0); - - msg = towire_dualopend_opener_init(NULL, - psbt, *amount, - oa->our_upfront_shutdown_script, - *feerate_per_kw, - *feerate_per_kw_funding, - channel->channel_flags, - *request_amt, - get_block_height(cmd->ld->topology), - true, - NULL); - - subd_send_msg(channel->owner, take(msg)); - return command_still_pending(cmd); - -} - static struct command_result *json_openchannel_init(struct command *cmd, const char *buffer, const jsmntok_t *obj UNNEEDED, @@ -3120,14 +3020,118 @@ static unsigned int dual_opend_msg(struct subd *dualopend, return 0; } +#if DEVELOPER +static struct command_result *json_queryrates(struct command *cmd, + const char *buffer, + const jsmntok_t *obj UNNEEDED, + const jsmntok_t *params) +{ + struct node_id *id; + struct peer *peer; + struct channel *channel; + u32 *feerate_per_kw_funding; + u32 *feerate_per_kw; + struct amount_sat *amount, *request_amt; + struct wally_psbt *psbt; + struct open_attempt *oa; + u8 *msg; + struct command_result *res; + + if (!param(cmd, buffer, params, + p_req("id", param_node_id, &id), + p_req("amount", param_sat, &amount), + p_req("request_amt", param_sat, &request_amt), + p_opt("commitment_feerate", param_feerate, &feerate_per_kw), + p_opt("funding_feerate", param_feerate, &feerate_per_kw_funding), + NULL)) + return command_param_failed(); + + res = init_set_feerate(cmd, &feerate_per_kw, &feerate_per_kw_funding); + if (res) + return res; + + peer = peer_by_id(cmd->ld, id); + if (!peer) { + return command_fail(cmd, FUNDING_UNKNOWN_PEER, "Unknown peer"); + } + + /* We can't query rates for a peer we have a channel with */ + channel = peer_active_channel(peer); + if (channel) + return command_fail(cmd, LIGHTNINGD, "Peer in state %s," + " can't query peer's rates if already" + " have a channel", + channel_state_name(channel)); + + channel = peer_unsaved_channel(peer); + if (!channel || !channel->owner) + return command_fail(cmd, FUNDING_PEER_NOT_CONNECTED, + "Peer not connected"); + if (channel->open_attempt + || !list_empty(&channel->inflights)) + return command_fail(cmd, FUNDING_STATE_INVALID, + "Channel funding in-progress. %s", + channel_state_name(channel)); + + if (!feature_negotiated(cmd->ld->our_features, + peer->their_features, + OPT_DUAL_FUND)) { + return command_fail(cmd, FUNDING_V2_NOT_SUPPORTED, + "v2 openchannel not supported " + "by peer, can't query rates"); + } + + /* BOLT #2: + * - if both nodes advertised `option_support_large_channel`: + * - MAY set `funding_satoshis` greater than or equal to 2^24 satoshi. + * - otherwise: + * - MUST set `funding_satoshis` to less than 2^24 satoshi. + */ + if (!feature_negotiated(cmd->ld->our_features, + peer->their_features, OPT_LARGE_CHANNELS) + && amount_sat_greater(*amount, chainparams->max_funding)) + return command_fail(cmd, FUND_MAX_EXCEEDED, + "Amount exceeded %s", + type_to_string(tmpctx, struct amount_sat, + &chainparams->max_funding)); + + /* Get a new open_attempt going, keeps us from re-initing + * while looking */ + channel->opener = LOCAL; + channel->open_attempt = oa = new_channel_open_attempt(channel); + channel->channel_flags = OUR_CHANNEL_FLAGS; + oa->funding = *amount; + oa->cmd = cmd; + /* empty psbt to start */ + psbt = create_psbt(tmpctx, 0, 0, 0); + + msg = towire_dualopend_opener_init(NULL, + psbt, *amount, + oa->our_upfront_shutdown_script, + *feerate_per_kw, + *feerate_per_kw_funding, + channel->channel_flags, + *request_amt, + get_block_height(cmd->ld->topology), + true, + NULL); + + subd_send_msg(channel->owner, take(msg)); + return command_still_pending(cmd); + +} + static const struct json_command queryrates_command = { - "queryrates", + "dev-queryrates", "channels", json_queryrates, "Ask a peer what their contribution and liquidity rates are" " for the given {amount} and {requested_amt}" }; +AUTODATA(json_command, &queryrates_command); +#endif /* DEVELOPER */ + static const struct json_command openchannel_init_command = { "openchannel_init", "channels", @@ -3166,7 +3170,6 @@ static const struct json_command openchannel_abort_command = { "Abort {channel_id}'s open. Usable while `commitment_signed=false`." }; -AUTODATA(json_command, &queryrates_command); AUTODATA(json_command, &openchannel_init_command); AUTODATA(json_command, &openchannel_update_command); AUTODATA(json_command, &openchannel_signed_command); diff --git a/tests/test_closing.py b/tests/test_closing.py index 58d413fbb0da..138344fc2372 100644 --- a/tests/test_closing.py +++ b/tests/test_closing.py @@ -729,6 +729,7 @@ def calc_lease_fee(amt, feerate, rates): @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') @pytest.mark.openchannel('v2') @pytest.mark.slow_test +@pytest.mark.developer("requres 'dev-queryrates'") def test_channel_lease_falls_behind(node_factory, bitcoind): ''' If our peer falls too far behind/doesn't send us an update for @@ -745,7 +746,7 @@ def test_channel_lease_falls_behind(node_factory, bitcoind): l2.fundwallet(20000000) l1.rpc.connect(l2.info['id'], 'localhost', l2.port) - rates = l1.rpc.queryrates(l2.info['id'], amount, amount) + rates = l1.rpc.dev_queryrates(l2.info['id'], amount, amount) l1.daemon.wait_for_log('disconnect') l1.rpc.connect(l2.info['id'], 'localhost', l2.port) # l1 leases a channel from l2 @@ -769,6 +770,7 @@ def test_channel_lease_falls_behind(node_factory, bitcoind): @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') @pytest.mark.openchannel('v2') @pytest.mark.slow_test +@pytest.mark.developer("requres 'dev-queryrates'") def test_channel_lease_closes(node_factory, bitcoind): ''' Check that channel leases work @@ -791,7 +793,7 @@ def test_channel_lease_closes(node_factory, bitcoind): l4.fundwallet(20000000) l1.rpc.connect(l2.info['id'], 'localhost', l2.port) - rates = l1.rpc.queryrates(l2.info['id'], amount, amount) + rates = l1.rpc.dev_queryrates(l2.info['id'], amount, amount) l1.daemon.wait_for_log('disconnect') l1.rpc.connect(l2.info['id'], 'localhost', l2.port) # l1 leases a channel from l2 @@ -812,7 +814,7 @@ def test_channel_lease_closes(node_factory, bitcoind): # l2 leases a channel from l3 l2.rpc.connect(l3.info['id'], 'localhost', l3.port) - rates = l2.rpc.queryrates(l3.info['id'], amount, amount) + rates = l2.rpc.dev_queryrates(l3.info['id'], amount, amount) l3.daemon.wait_for_log('disconnect') l2.rpc.connect(l3.info['id'], 'localhost', l3.port) l2.rpc.fundchannel(l3.info['id'], amount, request_amt=amount, @@ -915,6 +917,7 @@ def test_channel_lease_closes(node_factory, bitcoind): @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') @pytest.mark.openchannel('v2') @unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "Makes use of the sqlite3 db") +@pytest.mark.developer("requres 'dev-queryrates'") def test_channel_lease_lessor_cheat(node_factory, bitcoind, chainparams): ''' Check that lessee can recover funds if lessor cheats @@ -932,7 +935,7 @@ def test_channel_lease_lessor_cheat(node_factory, bitcoind, chainparams): l2.fundwallet(20000000) l1.rpc.connect(l2.info['id'], 'localhost', l2.port) - rates = l1.rpc.queryrates(l2.info['id'], amount, amount) + rates = l1.rpc.dev_queryrates(l2.info['id'], amount, amount) l1.daemon.wait_for_log('disconnect') l1.rpc.connect(l2.info['id'], 'localhost', l2.port) # l1 leases a channel from l2 @@ -987,6 +990,7 @@ def test_channel_lease_lessor_cheat(node_factory, bitcoind, chainparams): @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') @pytest.mark.openchannel('v2') @unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "Makes use of the sqlite3 db") +@pytest.mark.developer("requres 'dev-queryrates'") def test_channel_lease_lessee_cheat(node_factory, bitcoind, chainparams): ''' Check that lessor can recover funds if lessee cheats @@ -1004,7 +1008,7 @@ def test_channel_lease_lessee_cheat(node_factory, bitcoind, chainparams): l2.fundwallet(20000000) l1.rpc.connect(l2.info['id'], 'localhost', l2.port) - rates = l1.rpc.queryrates(l2.info['id'], amount, amount) + rates = l1.rpc.dev_queryrates(l2.info['id'], amount, amount) l1.daemon.wait_for_log('disconnect') l1.rpc.connect(l2.info['id'], 'localhost', l2.port) # l1 leases a channel from l2 diff --git a/tests/test_opening.py b/tests/test_opening.py index d8fa215c9ba4..d6e2533a4119 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -17,6 +17,7 @@ def find_next_feerate(node, peer): @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') @pytest.mark.openchannel('v2') +@pytest.mark.developer("requres 'dev-queryrates'") def test_queryrates(node_factory, bitcoind): l1, l2 = node_factory.get_nodes(2) @@ -26,7 +27,7 @@ def test_queryrates(node_factory, bitcoind): l2.fundwallet(amount * 10) l1.rpc.connect(l2.info['id'], 'localhost', l2.port) - result = l1.rpc.queryrates(l2.info['id'], amount, amount * 10) + result = l1.rpc.dev_queryrates(l2.info['id'], amount, amount * 10) assert result['our_funding_msat'] == Millisatoshi(amount * 1000) assert result['their_funding_msat'] == Millisatoshi(0) assert 'weight_charge' not in result @@ -42,7 +43,7 @@ def test_queryrates(node_factory, bitcoind): 'channel_fee_max_proportional_thousandths': 101}) l1.rpc.connect(l2.info['id'], 'localhost', l2.port) - result = l1.rpc.queryrates(l2.info['id'], amount, amount) + result = l1.rpc.dev_queryrates(l2.info['id'], amount, amount) assert result['our_funding_msat'] == Millisatoshi(amount * 1000) assert result['their_funding_msat'] == Millisatoshi(amount * 1000) assert result['funding_weight'] == 1000 From a87c3dfbbf68ab0e38e1543d36f642370f5e6ef0 Mon Sep 17 00:00:00 2001 From: niftynei Date: Wed, 7 Jul 2021 14:44:47 -0500 Subject: [PATCH 52/56] fixup! channel-lease: reject if we're not currently advertising liquidity --- tests/test_opening.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/test_opening.py b/tests/test_opening.py index d6e2533a4119..4bfd32ea42b0 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -27,10 +27,8 @@ def test_queryrates(node_factory, bitcoind): l2.fundwallet(amount * 10) l1.rpc.connect(l2.info['id'], 'localhost', l2.port) - result = l1.rpc.dev_queryrates(l2.info['id'], amount, amount * 10) - assert result['our_funding_msat'] == Millisatoshi(amount * 1000) - assert result['their_funding_msat'] == Millisatoshi(0) - assert 'weight_charge' not in result + with pytest.raises(RpcError, match=r'not advertising liquidity'): + l1.rpc.dev_queryrates(l2.info['id'], amount, amount * 10) l2.rpc.call('funderupdate', {'policy': 'match', 'policy_mod': 100, From 6187448c1058e542a72908c8c1373dcc678e68dc Mon Sep 17 00:00:00 2001 From: niftynei Date: Wed, 7 Jul 2021 15:51:51 -0500 Subject: [PATCH 53/56] reestablish_tlvs: don't lose them btw tmpctx cleanup --- openingd/dualopend.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 0be387b5c408..3805e5c93633 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -3488,7 +3488,7 @@ static void do_reconnect_dance(struct state *state) 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); + struct tlv_channel_reestablish_tlvs *tlvs = tlv_channel_reestablish_tlvs_new(NULL); #endif /* BOLT #2: @@ -3539,6 +3539,9 @@ static void do_reconnect_dance(struct state *state) peer_wire_name(fromwire_peektype(msg)), tal_hex(msg, msg)); +#if EXPERIMENTAL_FEATURES + tal_free(tlvs); +#endif /* EXPERIMENTAL_FEATURES */ check_channel_id(state, &cid, &state->channel_id); status_debug("Got dualopend reestablish commit=%"PRIu64 From 913b61133a28ad6f3a2b834db29b1a6e815a01dc Mon Sep 17 00:00:00 2001 From: niftynei Date: Wed, 7 Jul 2021 15:52:50 -0500 Subject: [PATCH 54/56] fixup! lease-channels: tests for the test gods --- tests/test_closing.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test_closing.py b/tests/test_closing.py index 138344fc2372..20303e520a71 100644 --- a/tests/test_closing.py +++ b/tests/test_closing.py @@ -785,6 +785,10 @@ def test_channel_lease_closes(node_factory, bitcoind): 'lease-fee-base-msat': '100sat', 'lease-fee-basis': 100, 'may_reconnect': True}) + + # Allow l2 some warnings + l2.allow_warning = True + feerate = 2000 amount = 500000 l1.fundwallet(20000000) From a29d9526d12bf1187c6e74bb8c68b17b3391e3c4 Mon Sep 17 00:00:00 2001 From: niftynei Date: Wed, 7 Jul 2021 15:53:47 -0500 Subject: [PATCH 55/56] fixup! funder: make policy a pointer, most places --- tests/test_opening.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_opening.py b/tests/test_opening.py index 4bfd32ea42b0..7e81f6bf0cf4 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -1015,7 +1015,7 @@ def test_funder_options(node_factory, bitcoind): assert funder_opts['per_channel_min'] == '10000000msat' assert funder_opts['per_channel_max'] == '4294967295000msat' assert funder_opts['reserve_tank'] == '0msat' - assert funder_opts['fuzz_percent'] == 5 + assert funder_opts['fuzz_percent'] == 0 assert funder_opts['fund_probability'] == 100 # l2 funds a chanenl with us. We don't contribute From 4e1946f65d11c7f078a6efa018fd6e15aaa23e5e Mon Sep 17 00:00:00 2001 From: niftynei Date: Wed, 7 Jul 2021 16:06:45 -0500 Subject: [PATCH 56/56] fixup! liquidity-ads: persist channel blockheight states to disk --- wallet/db_postgres_sqlgen.c | 2 +- wallet/db_sqlite3_sqlgen.c | 2 +- wallet/statements_gettextgen.po | 46 ++++++++++++++++----------------- wallet/wallet.c | 2 +- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/wallet/db_postgres_sqlgen.c b/wallet/db_postgres_sqlgen.c index 3f37ce43e430..145814864d95 100644 --- a/wallet/db_postgres_sqlgen.c +++ b/wallet/db_postgres_sqlgen.c @@ -2026,4 +2026,4 @@ struct db_query db_postgres_queries[] = { #endif /* LIGHTNINGD_WALLET_GEN_DB_POSTGRES */ -// SHA256STAMP:4d1da328c12739465826fac14dfba853b845ee1c752626f1767ef52a79471de7 +// SHA256STAMP:faf897ed266e0365697865648649c2107997bdf9923a8062b0256d314f7ff6db diff --git a/wallet/db_sqlite3_sqlgen.c b/wallet/db_sqlite3_sqlgen.c index e8699aede551..562cd9400820 100644 --- a/wallet/db_sqlite3_sqlgen.c +++ b/wallet/db_sqlite3_sqlgen.c @@ -2026,4 +2026,4 @@ struct db_query db_sqlite3_queries[] = { #endif /* LIGHTNINGD_WALLET_GEN_DB_SQLITE3 */ -// SHA256STAMP:4d1da328c12739465826fac14dfba853b845ee1c752626f1767ef52a79471de7 +// SHA256STAMP:faf897ed266e0365697865648649c2107997bdf9923a8062b0256d314f7ff6db diff --git a/wallet/statements_gettextgen.po b/wallet/statements_gettextgen.po index 4554b8cc91b3..1ef224ba153b 100644 --- a/wallet/statements_gettextgen.po +++ b/wallet/statements_gettextgen.po @@ -674,91 +674,91 @@ msgstr "" msgid "ALTER TABLE outputs ADD csv_lock INTEGER DEFAULT 1;" msgstr "" -#: wallet/db.c:978 +#: wallet/db.c:979 msgid "UPDATE vars SET intval = intval + 1 WHERE name = 'data_version' AND intval = ?" msgstr "" -#: wallet/db.c:1078 +#: wallet/db.c:1079 msgid "SELECT version FROM version LIMIT 1" msgstr "" -#: wallet/db.c:1140 +#: wallet/db.c:1141 msgid "UPDATE version SET version=?;" msgstr "" -#: wallet/db.c:1148 +#: wallet/db.c:1149 msgid "INSERT INTO db_upgrades VALUES (?, ?);" msgstr "" -#: wallet/db.c:1160 +#: wallet/db.c:1161 msgid "SELECT intval FROM vars WHERE name = 'data_version'" msgstr "" -#: wallet/db.c:1187 +#: wallet/db.c:1188 msgid "SELECT intval FROM vars WHERE name= ? LIMIT 1" msgstr "" -#: wallet/db.c:1203 +#: wallet/db.c:1204 msgid "UPDATE vars SET intval=? WHERE name=?;" msgstr "" -#: wallet/db.c:1212 +#: wallet/db.c:1213 msgid "INSERT INTO vars (name, intval) VALUES (?, ?);" msgstr "" -#: wallet/db.c:1226 +#: wallet/db.c:1227 msgid "UPDATE channels SET feerate_base = ?, feerate_ppm = ?;" msgstr "" -#: wallet/db.c:1247 +#: wallet/db.c:1248 msgid "UPDATE channels SET our_funding_satoshi = funding_satoshi WHERE funder = 0;" msgstr "" -#: wallet/db.c:1263 +#: wallet/db.c:1264 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:1325 +#: wallet/db.c:1326 msgid "UPDATE outputs SET scriptpubkey = ? WHERE prev_out_tx = ? AND prev_out_index = ?" msgstr "" -#: wallet/db.c:1350 +#: wallet/db.c:1351 msgid "SELECT id, funding_tx_id, funding_tx_outnum FROM channels;" msgstr "" -#: wallet/db.c:1369 +#: wallet/db.c:1370 msgid "UPDATE channels SET full_channel_id = ? WHERE id = ?;" msgstr "" -#: wallet/db.c:1390 +#: wallet/db.c:1391 msgid "SELECT channels.id, peers.node_id FROM channels JOIN peers ON (peers.id = channels.peer_id)" msgstr "" -#: wallet/db.c:1423 +#: wallet/db.c:1424 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:1456 +#: wallet/db.c:1457 msgid "INSERT INTO channel_blockheights (channel_id, hstate, blockheight) SELECT id, 4, 0 FROM channels WHERE funder = 0;" msgstr "" -#: wallet/db.c:1464 +#: wallet/db.c:1465 msgid "INSERT INTO channel_blockheights (channel_id, hstate, blockheight) SELECT id, 14, 0 FROM channels WHERE funder = 1;" msgstr "" -#: wallet/db.c:1476 +#: wallet/db.c:1477 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:1543 +#: wallet/db.c:1544 msgid "UPDATE channel_funding_inflights SET last_tx = ? WHERE channel_id = ? AND funding_tx_id = ?;" msgstr "" -#: wallet/db.c:1567 +#: wallet/db.c:1568 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:1634 +#: wallet/db.c:1635 msgid "UPDATE channels SET last_tx = ? WHERE id = ?;" msgstr "" @@ -1337,4 +1337,4 @@ msgstr "" #: wallet/test/run-wallet.c:1696 msgid "INSERT INTO channels (id) VALUES (1);" msgstr "" -# SHA256STAMP:c8431455ff375f6a6d9225082d2529a06e01ebf508690765721740d5af851987 +# SHA256STAMP:28f0ccfe94b0a41dd9f7053d1593beba6a833c6de80e510dbe7e26aca8f98ccf diff --git a/wallet/wallet.c b/wallet/wallet.c index 348460f02ef2..e9a26b611cee 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -1064,7 +1064,7 @@ void wallet_inflight_add(struct wallet *w, struct channel_inflight *inflight) db_bind_null(stmt, 9); db_bind_null(stmt, 10); db_bind_null(stmt, 11); - db_bind_null(stmt, 12); + db_bind_int(stmt, 12, 0); db_bind_null(stmt, 13); }