From 463626dbfd681c36e72740cb9fd61405e8a9b460 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 | 20 +-- 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 + plugins/topology.c | 5 +- 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 | 42 +++++- 18 files changed, 548 insertions(+), 37 deletions(-) create mode 100644 wire/extracted_peer_04_opt_will_fund.patch diff --git a/channeld/channeld.c b/channeld/channeld.c index dc614af9d1ca..f5a05242691d 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -2098,6 +2098,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 b37adfeab9c5..27a6cabcd7ce 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 common/test/run-bolt12_merkle: \ diff --git a/common/test/run-gossmap_local.c b/common/test/run-gossmap_local.c index 4973f9de79c1..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,26 +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, u64 *allow_extra 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) @@ -291,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 7defae9f434c..a3f23c7bc068 100644 --- a/gossipd/gossip_generation.c +++ b/gossipd/gossip_generation.c @@ -30,6 +30,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) @@ -38,13 +39,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 d13ba5e4652c..a10f3b0ae5fd 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 fabb469d6b55..0fd8c081587b 100644 --- a/gossipd/routing.c +++ b/gossipd/routing.c @@ -1598,6 +1598,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; @@ -1607,10 +1608,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; } @@ -1737,15 +1740,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 ce90d1cec49d..a920876515db 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -1251,6 +1251,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: @@ -1598,6 +1599,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: @@ -3344,6 +3346,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/plugins/topology.c b/plugins/topology.c index becc242b716b..6b81bc456e59 100644 --- a/plugins/topology.c +++ b/plugins/topology.c @@ -521,7 +521,9 @@ static void json_add_node(struct json_stream *js, struct node_id nid; struct wireaddr *addrs; struct json_escape *esc; + struct tlv_node_ann_tlvs *na_tlvs; + na_tlvs = tlv_node_ann_tlvs_new(tmpctx); if (!fromwire_node_announcement(nannounce, nannounce, &signature, &features, @@ -529,7 +531,8 @@ static void json_add_node(struct json_stream *js, &nid, rgb_color, alias, - &addresses)) { + &addresses, + na_tlvs)) { plugin_log(plugin, LOG_BROKEN, "Cannot parse stored node_announcement" " for %s at %u: %s", 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 f17e49bdc78a..e2685809ee8e 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:a3a508935b99ff0b985d0774432ae9d98f3ec7660bf4edf64095a3d0a37ba0e8 +// SHA256STAMP:4751c4834d5db7d170f8e1ee40ea8b5e12b5552780d37b099fe5fae6f0342c9e diff --git a/wire/peer_printgen.h b/wire/peer_printgen.h index 2caeaa7bd7c8..a3bd3d333fc4 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:a3a508935b99ff0b985d0774432ae9d98f3ec7660bf4edf64095a3d0a37ba0e8 +// SHA256STAMP:4751c4834d5db7d170f8e1ee40ea8b5e12b5552780d37b099fe5fae6f0342c9e 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 d32b9e42bf92..6cfe78176272 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 cae0d88b036d..92c206e9b6c2 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, NULL, 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:a3a508935b99ff0b985d0774432ae9d98f3ec7660bf4edf64095a3d0a37ba0e8 +// SHA256STAMP:4751c4834d5db7d170f8e1ee40ea8b5e12b5552780d37b099fe5fae6f0342c9e diff --git a/wire/peer_wiregen.h b/wire/peer_wiregen.h index 66d20b975de1..e063cfb846e2 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:a3a508935b99ff0b985d0774432ae9d98f3ec7660bf4edf64095a3d0a37ba0e8 +// SHA256STAMP:4751c4834d5db7d170f8e1ee40ea8b5e12b5552780d37b099fe5fae6f0342c9e diff --git a/wire/test/run-peer-wire.c b/wire/test/run-peer-wire.c index 160a889bbf35..1f2e4b7a8524 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,37 @@ 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) + 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 +1197,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 b5fc2ac26af12b2a60c19e929eae524cad394c4c 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 | 15 +++++++++++---- gossipd/gossipd.h | 4 ++++ lightningd/gossip_msg.c | 15 +++++++++++++++ lightningd/gossip_msg.h | 2 ++ 5 files changed, 42 insertions(+), 7 deletions(-) diff --git a/gossipd/gossip_generation.c b/gossipd/gossip_generation.c index a3f23c7bc068..d8e199157f16 100644 --- a/gossipd/gossip_generation.c +++ b/gossipd/gossip_generation.c @@ -26,7 +26,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; @@ -40,6 +41,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 @@ -165,7 +168,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) { @@ -208,7 +214,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 a10f3b0ae5fd..56e1e3400e3c 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,8 @@ static bool get_node_announcement(const tal_t *ctx, } *wireaddrs = fromwire_wireaddr_array(ctx, addresses); + *rates = tal_steal(ctx, na_tlvs->option_will_fund); + tal_free(addresses); return true; } @@ -208,14 +211,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 +926,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 +935,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, @@ -1552,6 +1558,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..2d54e42798e0 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 */ + const struct lease_rates *rates; }; struct range_query_reply { diff --git a/lightningd/gossip_msg.c b/lightningd/gossip_msg.c index 47eb5bb93e2b..7cdf681dfc17 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 fe1f48eca82d..b259705d93ec 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 cdb934ef92d600f2245c9ca2518976304d3eb001 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-check_channel_announcement.c | 3 +- gossipd/test/run-check_node_announcement.c | 147 ++++++++++++++++++ gossipd/test/run-txout_failure.c | 3 +- 6 files changed, 202 insertions(+), 15 deletions(-) create mode 100644 gossipd/test/run-check_node_announcement.c diff --git a/gossipd/gossip_generation.c b/gossipd/gossip_generation.c index d8e199157f16..a1fcd099db42 100644 --- a/gossipd/gossip_generation.c +++ b/gossipd/gossip_generation.c @@ -96,13 +96,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: * @@ -125,17 +126,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. */ @@ -143,8 +170,14 @@ bool nannounce_different(struct gossip_store *gs, get_nannounce_parts(orig, oparts, osizes); get_nannounce_parts(nannounce, nparts, nsizes); + if (only_missing_tlv) + *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 @@ -177,7 +210,8 @@ static void update_own_node_announcement(struct daemon *daemon) if (self && self->bcast.index) { u32 next; - if (!nannounce_different(daemon->rstate->gs, self, nannounce)) + if (!nannounce_different(daemon->rstate->gs, self, nannounce, + NULL)) 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 0fd8c081587b..54b70312ccc2 100644 --- a/gossipd/routing.c +++ b/gossipd/routing.c @@ -1656,6 +1656,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); @@ -1670,7 +1672,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-check_channel_announcement.c b/gossipd/test/run-check_channel_announcement.c index caaea2ca35d3..411ae4c604ce 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-txout_failure.c b/gossipd/test/run-txout_failure.c index 38cde87d4459..bc811554a80d 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 cbfd35e972b3f02a03e26d3f0d0307010c98b989 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 a1fcd099db42..35c6b83f269e 100644 --- a/gossipd/gossip_generation.c +++ b/gossipd/gossip_generation.c @@ -180,6 +180,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 @@ -187,8 +218,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. */ @@ -205,7 +235,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; @@ -227,6 +256,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, @@ -237,32 +267,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 @@ -271,8 +352,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 56e1e3400e3c..0b896bbfcd30 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -288,7 +288,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; } @@ -1131,7 +1131,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, @@ -1357,7 +1357,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 1adadee9e27e3da0e020891e74ef4dd50657eda9 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-Experimental: 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 0b896bbfcd30..722d0db8eb71 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -1409,6 +1409,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, @@ -1496,6 +1514,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 2dbd2b2245d7..1f41189a5d2c 100644 --- a/gossipd/gossipd_wire.csv +++ b/gossipd/gossipd_wire.csv @@ -1,6 +1,7 @@ #include #include #include +#include #include # Initialize the gossip daemon. @@ -118,3 +119,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 c54ac4b88bb6..08d36495503f 100644 --- a/gossipd/gossipd_wiregen.c +++ b/gossipd/gossipd_wiregen.c @@ -43,6 +43,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); @@ -75,6 +76,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; @@ -753,4 +755,26 @@ bool fromwire_gossipd_addgossip_reply(const tal_t *ctx, const void *p, wirestrin *err = fromwire_wirestring(ctx, &cursor, &plen); return cursor != NULL; } -// SHA256STAMP:9b38d439d81bbd471c821163b275c5cf3106a665dbdea563113742476f18e386 + +/* 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:c511c2859bffa718708c4cceedd59807d0a43cd48060a59bf7cbabfa2f6515f9 diff --git a/gossipd/gossipd_wiregen.h b/gossipd/gossipd_wiregen.h index c393c144840f..f1c39c19e069 100644 --- a/gossipd/gossipd_wiregen.h +++ b/gossipd/gossipd_wiregen.h @@ -10,6 +10,7 @@ #include #include #include +#include #include enum gossipd_wire { @@ -54,6 +55,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); @@ -178,6 +181,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:9b38d439d81bbd471c821163b275c5cf3106a665dbdea563113742476f18e386 +// SHA256STAMP:c511c2859bffa718708c4cceedd59807d0a43cd48060a59bf7cbabfa2f6515f9 diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index 1b2fd6a70175..acb0e851c5f4 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -138,6 +138,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_DEV_SET_MAX_SCIDS_ENCODE_SIZE: case WIRE_GOSSIPD_DEV_SUPPRESS: case WIRE_GOSSIPD_LOCAL_CHANNEL_CLOSE: @@ -243,6 +244,74 @@ void gossipd_notify_spend(struct lightningd *ld, subd_send_msg(ld->gossip, msg); } +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) /* Raw: comparison */ + return command_fail_badparam(cmd, "lease_fee_base_msat", + buffer, params, "Overflow"); + + if (channel_fee_base_msat->millisatoshis > rates->channel_fee_max_base_msat) /* Raw: comparison */ + 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); + /* Called upon receiving a addgossip_reply from `gossipd` */ static void json_addgossip_reply(struct subd *gossip UNUSED, const u8 *reply, const int *fds UNUSED, diff --git a/tests/test_gossip.py b/tests/test_gossip.py index d4bf19b207a1..37ffb42f621e 100644 --- a/tests/test_gossip.py +++ b/tests/test_gossip.py @@ -1095,6 +1095,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 de11c5db5502304757ffb00ec1abf661a06a39b2 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-Experimental: JSON-RPC: `listnodes` now includes the `lease_rates`, if available --- common/json_helpers.c | 14 ++++++++++++++ common/json_helpers.h | 5 +++++ plugins/topology.c | 6 ++++++ 3 files changed, 25 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/plugins/topology.c b/plugins/topology.c index 6b81bc456e59..9a263df64ea0 100644 --- a/plugins/topology.c +++ b/plugins/topology.c @@ -557,6 +557,12 @@ static void json_add_node(struct json_stream *js, for (size_t i = 0; i < tal_count(addrs); i++) json_add_address(js, NULL, &addrs[i]); json_array_end(js); + + if (na_tlvs->option_will_fund) { + json_object_start(js, "option_will_fund"); + json_add_lease_rates(js, na_tlvs->option_will_fund); + json_object_end(js); + } } out: json_object_end(js); From 0227cd112fddd11d5b9140403dbe46486cb867d7 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 f1ef5b65360d..43216f3359e9 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 e4b40204c649a6b8093368e296bec635d3345dff 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/Makefile | 1 + common/lease_rates.c | 17 +++++++++++++++++ common/lease_rates.h | 9 +++++++++ gossipd/Makefile | 1 + gossipd/gossipd.c | 8 ++++++-- 5 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 common/lease_rates.c create mode 100644 common/lease_rates.h diff --git a/common/Makefile b/common/Makefile index 21a22cd94995..0ca8359fbe2c 100644 --- a/common/Makefile +++ b/common/Makefile @@ -53,6 +53,7 @@ COMMON_SRC_NOGEN := \ common/key_derive.c \ common/keyset.c \ common/gossmap.c \ + common/lease_rates.c \ common/memleak.c \ common/msg_queue.c \ common/node_id.c \ 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 722d0db8eb71..2e09b7e6cedd 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -1418,8 +1419,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 d93b193e516c5564224de3f4c38699d1021aa435 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 | 78 ++++++++++++++++---------------- plugins/funder_policy.h | 14 +++--- plugins/test/run-funder_policy.c | 14 +++--- 4 files changed, 79 insertions(+), 75 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..79901fb75786 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,26 +61,27 @@ 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), @@ -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 5e5987b769197a9853d64e9be8711433c6405e57 Mon Sep 17 00:00:00 2001 From: niftynei Date: Wed, 14 Jul 2021 12:53:56 -0500 Subject: [PATCH 10/56] funder_policy: set default to 0 As we move to advertising liquidity, set the default to not have any fuzz. This means we won't randomly reject an offer to buy liquidity. --- plugins/funder_policy.c | 2 +- tests/test_opening.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/funder_policy.c b/plugins/funder_policy.c index 79901fb75786..69dabf9bd437 100644 --- a/plugins/funder_policy.c +++ b/plugins/funder_policy.c @@ -86,7 +86,7 @@ default_funder_policy(const tal_t *ctx, AMOUNT_SAT(UINT_MAX), AMOUNT_SAT(10000), AMOUNT_SAT(UINT_MAX), - 5, /* fuzz_factor */ + 0, /* fuzz_factor */ AMOUNT_SAT(0), /* reserve_tank */ 100); } diff --git a/tests/test_opening.py b/tests/test_opening.py index b3a20379734a..96e32586c24d 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -1000,7 +1000,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 3e40c830945cdb9ad7e09544dbf9c216ad6cd08b Mon Sep 17 00:00:00 2001 From: niftynei Date: Wed, 26 May 2021 18:13:08 -0500 Subject: [PATCH 11/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 c13808bbc7b8..778d13b89be1 100644 --- a/plugins/Makefile +++ b/plugins/Makefile @@ -118,6 +118,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 \ @@ -151,7 +152,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 5c5e7a1c2b0ad93ab52a1f87801899fad2191e91 Mon Sep 17 00:00:00 2001 From: niftynei Date: Sat, 29 May 2021 14:01:19 -0500 Subject: [PATCH 12/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 8aedc13305b931eda9bef75daedc8fb1bfd6661f Mon Sep 17 00:00:00 2001 From: niftynei Date: Wed, 26 May 2021 18:16:07 -0500 Subject: [PATCH 13/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 37ffb42f621e..1cc3a5443bbf 100644 --- a/tests/test_gossip.py +++ b/tests/test_gossip.py @@ -939,6 +939,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 1dd656c8b7130ff70c9f972c3494cb1041481c7c 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 988894ce2a30..7413812ad5ac 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 c94b4e6a4ec6dfd9fbaf01a67ff06e7a652aeca0 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 57ef6734a536..587250c956e1 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:d802e57862a2ced1580824c7419e6c1075864496478c7ca6c47456df279d88df + +/* 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:c1ec339d1925da25ee587ffb4fb5e35d0b3c578e525f519384c8fecc1054dc2a diff --git a/hsmd/hsmd_wiregen.h b/hsmd/hsmd_wiregen.h index 1e64236ced5a..7fbabc6a61a5 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:d802e57862a2ced1580824c7419e6c1075864496478c7ca6c47456df279d88df +// SHA256STAMP:c1ec339d1925da25ee587ffb4fb5e35d0b3c578e525f519384c8fecc1054dc2a 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 03fb9e34763ef97387bda6f0210c517cc251a78d 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-Experimental: 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 4f204cb885f4..feb715484c35 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 7413812ad5ac..0eeac2b52e5c 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 26e739ac032be138a68d23e818110d3892764dc7 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-Experimental: 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 e664c54bdf14..e407e107ccb6 100644 --- a/contrib/pyln-client/pyln/client/lightning.py +++ b/contrib/pyln-client/pyln/client/lightning.py @@ -1009,7 +1009,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, @@ -1019,6 +1019,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 be59860ebec2..3c449a82283c 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, an object is returned, containing: @@ -63,6 +68,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: @@ -105,4 +119,4 @@ lightning-fundchannel_\fBcomplete\fR(7), \fBlightning-fundchannel\fR(7), Main web site: \fIhttps://github.com/ElementsProject/lightning\fR -\" SHA256STAMP:ba03cf64c3578303a0cdfcf94546bb94d86ecf3d6187b16871a39c08b3a40f38 +\" SHA256STAMP:13023bb80ee4a7f6a94a168399a01e05c6c5ab68e9eec5795ebd5f49207a03ac diff --git a/doc/lightning-openchannel_init.7.md b/doc/lightning-openchannel_init.7.md index 36c187c49c93..b3493557f852 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 ------------ @@ -53,6 +57,14 @@ On success, an object is returned, containing: 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 0eeac2b52e5c..a2a2d86b1b8f 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; @@ -2343,7 +2346,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; @@ -2357,6 +2360,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(); @@ -2488,7 +2492,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 a920876515db..8db2a7daa02e 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) @@ -1908,7 +1911,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; @@ -1943,6 +1947,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 @@ -2006,7 +2023,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); @@ -2021,7 +2040,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) @@ -2031,6 +2051,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)) @@ -2400,7 +2433,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, @@ -2409,7 +2443,9 @@ static void opener_start(struct state *state, u8 *msg) &state->upfront_shutdown_script[LOCAL], &state->feerate_per_kw_commitment, &tx_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; @@ -2438,6 +2474,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 53f52e103eaa..397b2ccbe10d 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? @@ -79,6 +80,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 @@ -86,6 +89,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 f084ddd03da6..5aa955466c3b 100644 --- a/openingd/dualopend_wiregen.c +++ b/openingd/dualopend_wiregen.c @@ -247,7 +247,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); @@ -266,10 +266,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; @@ -293,12 +295,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); @@ -308,10 +312,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; @@ -326,6 +336,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:2aa38c967abfcd0110b6c65f62b13aa77cefacaf5f036a9217bb5d63220f1e1f +// SHA256STAMP:d8a31a5de292561ccfb5b7050c911b590db44a50209e02469179904708328861 diff --git a/openingd/dualopend_wiregen.h b/openingd/dualopend_wiregen.h index d71ca4574faa..2ef8db7b3561 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:2aa38c967abfcd0110b6c65f62b13aa77cefacaf5f036a9217bb5d63220f1e1f +// SHA256STAMP:d8a31a5de292561ccfb5b7050c911b590db44a50209e02469179904708328861 From 25499e08f57bd6410df1aab4ffbe156f9e8ce600 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 e407e107ccb6..74bf559385b5 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 51dc7de65543..3180e88b8693 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:d25fc36b745b6f58556f7f4b06f23ff83b466d4a00911f7ffdc9d86572902954 +\" SHA256STAMP:c7cd9291a08e66e41b24d0045c313ac1e3dabcb4579ab5fe132aad8d1ecbb640 diff --git a/doc/lightning-fundchannel.7.md b/doc/lightning-fundchannel.7.md index 770efa4ea827..125fc92048cf 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 7c1e7e23fcd0..c86e9ea5570d 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 @@ -204,4 +208,4 @@ ZmnSCPxj \fI is mainly responsible\. Main web site: \fIhttps://github.com/ElementsProject/lightning\fR -\" SHA256STAMP:86b05635f6d0d55dc3771779237bf1046b52f8cd290f16cccc5656cb94f2863a +\" SHA256STAMP:fa55ac01a568d6b816641ddbfa3c9cccf437dea06df5ec84747f7ef02db6d47e diff --git a/doc/lightning-multifundchannel.7.md b/doc/lightning-multifundchannel.7.md index 4f6c43b1ef05..a0472f9d4db7 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 93a848f3231558ccfa729884d4a50556c7409e1f 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 a2a2d86b1b8f..395aaeb1720e 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -2893,7 +2893,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", @@ -2959,7 +2960,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 8db2a7daa02e..6f94056ff679 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -1904,6 +1904,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; @@ -2128,6 +2173,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 3210dd8d7eee9b05689931b4ab66a38af1f63be8 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 395aaeb1720e..6d4b603facaa 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -2335,10 +2335,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; @@ -2350,6 +2373,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, @@ -2389,20 +2413,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 a4968b6f3a8ef3b000381a965f0432860d49f158 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 --- 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 | 37 ++++++++ 6 files changed, 279 insertions(+), 9 deletions(-) diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index 6d4b603facaa..d84817d675b7 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; @@ -2358,6 +2395,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, @@ -2507,7 +2643,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); @@ -2801,6 +2938,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; @@ -2851,6 +2991,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", @@ -2889,6 +3037,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 6f94056ff679..2dc6eaac2d16 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -2004,7 +2004,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 @@ -2492,6 +2491,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, @@ -2502,7 +2502,8 @@ static void opener_start(struct state *state, u8 *msg) &tx_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; @@ -2620,6 +2621,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)) @@ -3387,6 +3413,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 397b2ccbe10d..2cf80caa98cc 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 5aa955466c3b..97ed07980e58 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:d8a31a5de292561ccfb5b7050c911b590db44a50209e02469179904708328861 + +/* 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:a0ce1d5dfc6518a35d2e346c770754c498558ac426e3040526e10bbbc237db6f diff --git a/openingd/dualopend_wiregen.h b/openingd/dualopend_wiregen.h index 2ef8db7b3561..66bb3de80503 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:d8a31a5de292561ccfb5b7050c911b590db44a50209e02469179904708328861 +// SHA256STAMP:a0ce1d5dfc6518a35d2e346c770754c498558ac426e3040526e10bbbc237db6f diff --git a/tests/test_opening.py b/tests/test_opening.py index 96e32586c24d..c38e4eb3a647 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -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 9f3d9adfb73b6940f3099d5edbad428d368f3544 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 d84817d675b7..3019ca97cc3c 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) { @@ -2929,6 +2995,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; @@ -2967,6 +3036,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 2dc6eaac2d16..26be290b9ade 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -2182,7 +2183,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, @@ -2490,7 +2491,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; @@ -2643,8 +2644,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, @@ -3399,6 +3422,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: @@ -3414,6 +3438,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 2cf80caa98cc..36846061a3f4 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 97ed07980e58..3fe527a87a04 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:a0ce1d5dfc6518a35d2e346c770754c498558ac426e3040526e10bbbc237db6f + +/* 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:41650a0d42866067279024744de6ef7e52ff0ef5a406c4be3b702f1ecf11e556 diff --git a/openingd/dualopend_wiregen.h b/openingd/dualopend_wiregen.h index 66bb3de80503..35263d2060a6 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:a0ce1d5dfc6518a35d2e346c770754c498558ac426e3040526e10bbbc237db6f +// SHA256STAMP:41650a0d42866067279024744de6ef7e52ff0ef5a406c4be3b702f1ecf11e556 From f1b0660d633275acc6fd72b652e04733a7a02515 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 26be290b9ade..2924e976ba85 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -192,6 +192,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 @@ -2491,7 +2494,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; @@ -2642,16 +2645,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); @@ -2666,8 +2674,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, + tx_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 ade8db88fc634d1af0079d728bcefa2ee662591c 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 2924e976ba85..0567e4caedc6 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) @@ -192,9 +195,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 @@ -2212,6 +2212,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, + tx_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) */ @@ -2655,11 +2696,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); @@ -2706,7 +2747,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 d834de2d8b49e9dd422b22e1f763d0ec7b7c76e0 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 bb25dada9c617eb66b55ed66019ea3cf3539cb8f 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 | 39 +++++++++++++++++++++++---- bitcoin/script.h | 6 ++--- 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, 72 insertions(+), 22 deletions(-) diff --git a/bitcoin/script.c b/bitcoin/script.c index cbf45858b095..d4b7db9629fe 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,28 @@ u8 **bitcoin_witness_sig_and_element(const tal_t *ctx, * OP_ENDIF * OP_CHECKSIG */ +/* 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 lease_remaining, const struct pubkey *revocation_pubkey, const struct pubkey *local_delayedkey) { @@ -529,7 +558,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(lease_remaining, 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..807bd830e866 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,8 @@ 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 lease_remaining, 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 fb01cd175e0a..15b59f306ca0 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 fd331efdc2a2e53f3cd6375a879e9b61f4ea8ecf 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 f5a05242691d..5bee06853a63 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -3568,6 +3568,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 15b59f306ca0..31b133ddfa8a 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 0567e4caedc6..573d0b0d6ef9 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -1672,6 +1672,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( @@ -1768,6 +1769,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( @@ -2356,6 +2358,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, @@ -3732,6 +3735,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 8ebb3da94fa9..22c07ee27cd2 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 de7d3a03b255471946801df0d1b8f479b90088f4 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 f707bdb0fc4d34069114d7b83a2c80dc4a23ca03 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 | 8 + 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, 613 insertions(+), 196 deletions(-) diff --git a/common/initial_channel.c b/common/initial_channel.c index 31b133ddfa8a..3cf1b1e107b6 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 d3f4f8dc2b99..2dbf8d54b81e 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 3019ca97cc3c..88302d836279 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; @@ -2804,8 +2835,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; @@ -2815,6 +2847,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, @@ -2836,7 +2869,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)); @@ -2877,7 +2914,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)", @@ -2906,7 +2947,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)", @@ -3255,7 +3300,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 6add3f9e40ea..bf4fd543f856 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 aca62bdaeff5..f2d9a36c6cef 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -1344,6 +1344,14 @@ 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; + tal_free(channel->lease_commit_sig); + 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 573d0b0d6ef9..05f0d1ba3756 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; @@ -560,6 +574,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, @@ -706,8 +721,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); @@ -1693,6 +1718,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]; @@ -1727,6 +1753,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" @@ -1894,7 +1921,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); @@ -1911,17 +1942,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))) @@ -1929,7 +1962,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)); @@ -1952,7 +1986,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) @@ -1962,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; + 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; @@ -2186,9 +2226,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, @@ -2216,8 +2257,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; @@ -2252,8 +2291,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 @@ -2263,7 +2304,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); @@ -2300,6 +2342,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; @@ -2333,6 +2376,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 " @@ -2527,7 +2571,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); } @@ -2537,7 +2585,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; @@ -2697,7 +2745,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; @@ -2749,8 +2796,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, @@ -2815,7 +2870,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); @@ -2914,9 +2969,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) @@ -3726,7 +3784,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 36846061a3f4..1a7c48b9d78b 100644 --- a/openingd/dualopend_wire.csv +++ b/openingd/dualopend_wire.csv @@ -65,6 +65,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 3fe527a87a04..19b218690974 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 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 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); @@ -194,10 +194,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 *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 *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; @@ -248,6 +257,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:41650a0d42866067279024744de6ef7e52ff0ef5a406c4be3b702f1ecf11e556 +// SHA256STAMP:ee275d023d9d8ba7e520d321908da0228f76e7ca0d6f76908d17e967177f16c8 diff --git a/openingd/dualopend_wiregen.h b/openingd/dualopend_wiregen.h index 35263d2060a6..d568b6ee3abc 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 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 *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 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 *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:41650a0d42866067279024744de6ef7e52ff0ef5a406c4be3b702f1ecf11e556 +// SHA256STAMP:ee275d023d9d8ba7e520d321908da0228f76e7ca0d6f76908d17e967177f16c8 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 894beaf35903..d6f6abf0549b 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:8f8494fdeb030b724d84aa26c0377e7e488ad40e4b1370db7d02470ac29c4ec8 +// SHA256STAMP:85d581977cc3b124df4c81058cab78f13938dfa0cb4845526bb121e396bcf97d diff --git a/wallet/db_sqlite3_sqlgen.c b/wallet/db_sqlite3_sqlgen.c index d02ed9fbae14..b14a92fc95b4 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:8f8494fdeb030b724d84aa26c0377e7e488ad40e4b1370db7d02470ac29c4ec8 +// SHA256STAMP:85d581977cc3b124df4c81058cab78f13938dfa0cb4845526bb121e396bcf97d diff --git a/wallet/statements_gettextgen.po b/wallet/statements_gettextgen.po index 44339e8eb873..d174f8683371 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:cc1be3f6b134130e9c0251467bd7ecb8a7cdb20f3026bdd26fcf5b286872ef2c +# SHA256STAMP:c11c71bfdabd0f5e28d6d8b7539e2a1b7315206fb4df5c2870a658ea9c66c1c6 diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 1ad0c83ac3c7..38794dc810ca 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 817e5cece9d2d5b9b3390d7df05a987345dbc15a Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 22 Jun 2021 13:25:59 -0500 Subject: [PATCH 30/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 | 16 +- 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/bolt12_wiregen.c | 2 +- wire/bolt12_wiregen.h | 2 +- wire/common_wiregen.c | 2 +- wire/common_wiregen.h | 2 +- wire/onion_printgen.c | 2 +- wire/onion_printgen.h | 2 +- wire/onion_wiregen.c | 2 +- wire/onion_wiregen.h | 2 +- wire/peer_printgen.c | 2 +- wire/peer_printgen.h | 2 +- wire/peer_wiregen.c | 2 +- wire/peer_wiregen.h | 2 +- 72 files changed, 1414 insertions(+), 441 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 5bee06853a63..6e8cef587e9f 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) { @@ -1140,6 +1212,41 @@ static bool want_fee_update(const struct peer *peer, u32 *target) return val != current; } +/* 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; @@ -1150,6 +1257,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 @@ -1218,6 +1326,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: @@ -1226,9 +1350,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); @@ -2099,8 +2227,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; @@ -3172,6 +3300,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; @@ -3350,6 +3521,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; @@ -3438,7 +3614,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; @@ -3459,6 +3636,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, @@ -3529,7 +3709,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), @@ -3538,7 +3719,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); @@ -3568,7 +3751,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 7fd521e2140c..66bf7d957f0e 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, @@ -227,3 +231,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 be5e88e3330d..53082063e9db 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, const u8 *reestablish_only) +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, const u8 *reestablish_only) { u16 num_last_sent_commit = tal_count(last_sent_commit); u16 num_existing_htlcs = tal_count(htlcs); @@ -118,6 +120,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); @@ -192,7 +197,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, u8 **reestablish_only) +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, u8 **reestablish_only) { u16 num_last_sent_commit; u16 num_existing_htlcs; @@ -215,6 +220,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); @@ -1145,4 +1153,26 @@ bool fromwire_channeld_upgraded(const void *p, bool *option_static_remotekey) *option_static_remotekey = fromwire_bool(&cursor, &plen); return cursor != NULL; } -// SHA256STAMP:7fe345eb02876c231759ec37daba697e85ac3a43137e4b7cb67d136587e2bda5 + +/* 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:40a8d4ea75d57eeddfb5cc648a9ca3e3914dfe500a6054b6a6942f4023a17d82 diff --git a/channeld/channeld_wiregen.h b/channeld/channeld_wiregen.h index 6854874b8018..f53e5e9a4860 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, const u8 *reestablish_only); -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 **reestablish_only); +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, const u8 *reestablish_only); +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, u8 **reestablish_only); /* 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:7fe345eb02876c231759ec37daba697e85ac3a43137e4b7cb67d136587e2bda5 +// SHA256STAMP:40a8d4ea75d57eeddfb5cc648a9ca3e3914dfe500a6054b6a6942f4023a17d82 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..db33e6ec5727 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, REMOTE, &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 9c840a5a0a99..e8c766b39a27 100644 --- a/closingd/closingd_wiregen.c +++ b/closingd/closingd_wiregen.c @@ -195,4 +195,4 @@ bool fromwire_closingd_complete(const void *p) return false; return cursor != NULL; } -// SHA256STAMP:a8b0af1ae87e71bc448585060b8d449c3e5f0d0f4f3ac195dcd4d84f8176ae17 +// SHA256STAMP:681e83ed1e1950220b1e9dbf168e5583e23120981b9a084eab5bc6ce1bc9a1aa diff --git a/closingd/closingd_wiregen.h b/closingd/closingd_wiregen.h index b948b737fc3c..7d46f18b63f3 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:a8b0af1ae87e71bc448585060b8d449c3e5f0d0f4f3ac195dcd4d84f8176ae17 +// SHA256STAMP:681e83ed1e1950220b1e9dbf168e5583e23120981b9a084eab5bc6ce1bc9a1aa 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 3cf1b1e107b6..f65e6a35d428 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,13 @@ struct channel *new_initial_channel(const tal_t *ctx, /* takes() if necessary */ channel->fee_states = dup_fee_states(channel, fee_states); + /* takes() if necessary */ + if (!height_states) + channel->blockheight_states = NULL; + else + channel->blockheight_states + = dup_height_states(channel, height_states); + channel->view[LOCAL].owed[LOCAL] = channel->view[REMOTE].owed[LOCAL] = local_msatoshi; @@ -108,8 +117,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], 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 3ffd2af45de1..fa756278e897 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:9eae5e1735b52e459db2548ff73399a8cb503ddbf72defc5bfa4022f3682ffd5 +// SHA256STAMP:db80a04b587e0918ef55f7e82519f7ff86620c5ec4fd845452214059c1cdbd41 diff --git a/common/peer_status_wiregen.h b/common/peer_status_wiregen.h index a1bc77494658..94978e02cec7 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:9eae5e1735b52e459db2548ff73399a8cb503ddbf72defc5bfa4022f3682ffd5 +// SHA256STAMP:db80a04b587e0918ef55f7e82519f7ff86620c5ec4fd845452214059c1cdbd41 diff --git a/common/status_wiregen.c b/common/status_wiregen.c index dce8d303abc7..90da24ae2783 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:676725f967cd09851ed0d872ed58ed058fa9de7d95acca7169e0262e7d0b2c64 +// SHA256STAMP:6f868de7019bd204be0d90618a044c20ec1170430e3196674040ddb7f7278e80 diff --git a/common/status_wiregen.h b/common/status_wiregen.h index 81c2a6ee79c7..202ac0143bbd 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:676725f967cd09851ed0d872ed58ed058fa9de7d95acca7169e0262e7d0b2c64 +// SHA256STAMP:6f868de7019bd204be0d90618a044c20ec1170430e3196674040ddb7f7278e80 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 f25aa2b08cb7..1830b4707dc3 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:5565fac68fbf90e24ef5f8230483b52952d342080d44ce9fb8ae0e9843ad1529 +// SHA256STAMP:a115dcd604f1bcbe48bf57b25bfc2b59ec7eff3c4790812fa1c460aee2b50811 diff --git a/connectd/connectd_gossipd_wiregen.h b/connectd/connectd_gossipd_wiregen.h index 81f12781558b..2dfc3b12b4f2 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:5565fac68fbf90e24ef5f8230483b52952d342080d44ce9fb8ae0e9843ad1529 +// SHA256STAMP:a115dcd604f1bcbe48bf57b25bfc2b59ec7eff3c4790812fa1c460aee2b50811 diff --git a/connectd/connectd_wiregen.c b/connectd/connectd_wiregen.c index 122ad6021799..63e764fa3644 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:533fec0547d283247c2fbd2ef52c7df86614f5152c8f3282e0e1e699de3af5d4 +// SHA256STAMP:27a03f6c7a77a83be6fc4d063fd37d4bc47e7280310f19d72859ff3f409e05ca diff --git a/connectd/connectd_wiregen.h b/connectd/connectd_wiregen.h index 42acf72a8c06..e4f5c6504207 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:533fec0547d283247c2fbd2ef52c7df86614f5152c8f3282e0e1e699de3af5d4 +// SHA256STAMP:27a03f6c7a77a83be6fc4d063fd37d4bc47e7280310f19d72859ff3f409e05ca diff --git a/devtools/Makefile b/devtools/Makefile index a9c532fe5ce0..76ef117bdbab 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 918cecbdccc3..7dee245adcb5 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:f5b4fcddb25b45895865636a90b9a5e0f9d2acfba04f4e9ecc14d2dfcad1e01a +// SHA256STAMP:a709d2e8f179fb393064e210e72f1118fd60f67134d5f94fe33dc58a62f38ff7 diff --git a/gossipd/gossip_store_wiregen.h b/gossipd/gossip_store_wiregen.h index a7c4b3a1114f..8788114fb449 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:f5b4fcddb25b45895865636a90b9a5e0f9d2acfba04f4e9ecc14d2dfcad1e01a +// SHA256STAMP:a709d2e8f179fb393064e210e72f1118fd60f67134d5f94fe33dc58a62f38ff7 diff --git a/gossipd/gossipd_peerd_wiregen.c b/gossipd/gossipd_peerd_wiregen.c index caffb94f9dcb..f44c95924881 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:bf705b59df34f8e21f337759dfd6d56e610be91c1838a1eef25c807d5b2e7184 +// SHA256STAMP:3b60c444839f3c615c80609a295f43fd95f1bd6e9b4a66e56c95cf0e4e7607b1 diff --git a/gossipd/gossipd_peerd_wiregen.h b/gossipd/gossipd_peerd_wiregen.h index 5274f1ee2f17..5dd30cd8a81c 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:bf705b59df34f8e21f337759dfd6d56e610be91c1838a1eef25c807d5b2e7184 +// SHA256STAMP:3b60c444839f3c615c80609a295f43fd95f1bd6e9b4a66e56c95cf0e4e7607b1 diff --git a/gossipd/gossipd_wiregen.c b/gossipd/gossipd_wiregen.c index 08d36495503f..0c0b3171bcc2 100644 --- a/gossipd/gossipd_wiregen.c +++ b/gossipd/gossipd_wiregen.c @@ -777,4 +777,4 @@ bool fromwire_gossipd_new_lease_rates(const void *p, struct lease_rates *rates) fromwire_lease_rates(&cursor, &plen, rates); return cursor != NULL; } -// SHA256STAMP:c511c2859bffa718708c4cceedd59807d0a43cd48060a59bf7cbabfa2f6515f9 +// SHA256STAMP:a0408d2e1f668c085378bc2729e08d8712a95edc48d12df8c6cbf063aeddbf32 diff --git a/gossipd/gossipd_wiregen.h b/gossipd/gossipd_wiregen.h index f1c39c19e069..7a21446be492 100644 --- a/gossipd/gossipd_wiregen.h +++ b/gossipd/gossipd_wiregen.h @@ -188,4 +188,4 @@ bool fromwire_gossipd_new_lease_rates(const void *p, struct lease_rates *rates); #endif /* LIGHTNING_GOSSIPD_GOSSIPD_WIREGEN_H */ -// SHA256STAMP:c511c2859bffa718708c4cceedd59807d0a43cd48060a59bf7cbabfa2f6515f9 +// SHA256STAMP:a0408d2e1f668c085378bc2729e08d8712a95edc48d12df8c6cbf063aeddbf32 diff --git a/hsmd/hsmd_wiregen.c b/hsmd/hsmd_wiregen.c index 587250c956e1..1ffce0751a96 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:c1ec339d1925da25ee587ffb4fb5e35d0b3c578e525f519384c8fecc1054dc2a +// SHA256STAMP:5cc29ba49eb086d023342733bcaeb16b5b8e3c5b7b9d5826e70dd4f46b0d1dd2 diff --git a/hsmd/hsmd_wiregen.h b/hsmd/hsmd_wiregen.h index 7fbabc6a61a5..830d52f62c3a 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:c1ec339d1925da25ee587ffb4fb5e35d0b3c578e525f519384c8fecc1054dc2a +// SHA256STAMP:5cc29ba49eb086d023342733bcaeb16b5b8e3c5b7b9d5826e70dd4f46b0d1dd2 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 2dbf8d54b81e..19611944597b 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 1df8e749f1dc..02d0f4b42db1 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); } @@ -451,6 +478,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: @@ -587,6 +615,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, @@ -647,9 +678,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, @@ -757,7 +792,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 88302d836279..34fd7d5ba6f5 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; @@ -2837,7 +2850,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; @@ -2870,6 +2883,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, @@ -2915,6 +2929,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, @@ -2951,7 +2966,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)", @@ -3224,7 +3240,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; @@ -3268,6 +3284,8 @@ void peer_restart_dualopend(struct peer *peer, inflight = channel_current_inflight(channel); assert(inflight); + blockheight = get_blockheight(channel->blockheight_states, + channel->opener, LOCAL); msg = towire_dualopend_reinit(NULL, chainparams, @@ -3301,6 +3319,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 bf4fd543f856..995acc76252a 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 f2d9a36c6cef..b0aaf76ae38c 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -1352,6 +1352,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 e5ccd4c75fe6..d16263f540ab 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -454,6 +454,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 a42f776e8bf3..b8656a6c6a1b 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:746e39c14fccea8ff63ee097aa2b742ff0cdb63bd6dfaecd02b8b1c9fab58376 +// SHA256STAMP:40630b923c5c303627b75b8ca663b0d8a060039d2171571f6ecab580695dfdba diff --git a/onchaind/onchaind_wiregen.h b/onchaind/onchaind_wiregen.h index 7b6cc57511e2..7f9de0d68d0a 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:746e39c14fccea8ff63ee097aa2b742ff0cdb63bd6dfaecd02b8b1c9fab58376 +// SHA256STAMP:40630b923c5c303627b75b8ca663b0d8a060039d2171571f6ecab580695dfdba 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 05f0d1ba3756..4bf1dee01a07 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; @@ -1697,6 +1702,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, @@ -1796,6 +1803,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, @@ -1922,6 +1932,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, @@ -2003,7 +2014,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; @@ -2043,12 +2053,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. @@ -2115,7 +2123,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); @@ -2228,7 +2236,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, @@ -2258,7 +2266,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 @@ -2402,6 +2410,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, @@ -2572,6 +2582,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, @@ -2586,7 +2597,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; @@ -2598,7 +2608,7 @@ static void opener_start(struct state *state, u8 *msg) &tx_state->feerate_per_kw_funding, &state->channel_flags, &requested_sats, - ¤t_blockheight, + &tx_state->blockheight, &dry_run)) master_badmsg(WIRE_DUALOPEND_OPENER_INIT, msg); @@ -2633,7 +2643,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, @@ -2746,7 +2756,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, @@ -3785,6 +3795,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, @@ -3797,6 +3808,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 1a7c48b9d78b..823b790ef4a0 100644 --- a/openingd/dualopend_wire.csv +++ b/openingd/dualopend_wire.csv @@ -65,6 +65,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 19b218690974..54083001c7c8 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 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 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); @@ -194,6 +194,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); @@ -206,7 +207,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 *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 *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; @@ -257,6 +258,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:ee275d023d9d8ba7e520d321908da0228f76e7ca0d6f76908d17e967177f16c8 +// SHA256STAMP:65d1bedd1e05436c5474d298811fbb9c3fc96ac4e84bef8081c4eee55de286ad diff --git a/openingd/dualopend_wiregen.h b/openingd/dualopend_wiregen.h index d568b6ee3abc..efbfb40d2054 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 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 *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 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 *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:ee275d023d9d8ba7e520d321908da0228f76e7ca0d6f76908d17e967177f16c8 +// SHA256STAMP:65d1bedd1e05436c5474d298811fbb9c3fc96ac4e84bef8081c4eee55de286ad diff --git a/openingd/openingd.c b/openingd/openingd.c index 22c07ee27cd2..113210d8cdd6 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 993782631fc2..be6688027f3e 100644 --- a/openingd/openingd_wiregen.c +++ b/openingd/openingd_wiregen.c @@ -604,4 +604,4 @@ bool fromwire_openingd_dev_memleak_reply(const void *p, bool *leak) *leak = fromwire_bool(&cursor, &plen); return cursor != NULL; } -// SHA256STAMP:3dc596105e65c16cc549a7ae739c7e83ed11cce7d7effb206f317522ba741506 +// SHA256STAMP:779aa98c325bc5c87c31b24767f45f22edd135b8e2be4fe3ca1282d91950f0c4 diff --git a/openingd/openingd_wiregen.h b/openingd/openingd_wiregen.h index 949010fdf059..d319eb102079 100644 --- a/openingd/openingd_wiregen.h +++ b/openingd/openingd_wiregen.h @@ -128,4 +128,4 @@ bool fromwire_openingd_dev_memleak_reply(const void *p, bool *leak); #endif /* LIGHTNING_OPENINGD_OPENINGD_WIREGEN_H */ -// SHA256STAMP:3dc596105e65c16cc549a7ae739c7e83ed11cce7d7effb206f317522ba741506 +// SHA256STAMP:779aa98c325bc5c87c31b24767f45f22edd135b8e2be4fe3ca1282d91950f0c4 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 d6f6abf0549b..5f945e52120a 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:85d581977cc3b124df4c81058cab78f13938dfa0cb4845526bb121e396bcf97d +// SHA256STAMP:1778bd4f49bef247c2b4789d1f7db3542fd606cbe186e299738aecbfbb2d44ae diff --git a/wallet/db_sqlite3_sqlgen.c b/wallet/db_sqlite3_sqlgen.c index b14a92fc95b4..130e28603a64 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:85d581977cc3b124df4c81058cab78f13938dfa0cb4845526bb121e396bcf97d +// SHA256STAMP:1778bd4f49bef247c2b4789d1f7db3542fd606cbe186e299738aecbfbb2d44ae diff --git a/wallet/statements_gettextgen.po b/wallet/statements_gettextgen.po index d174f8683371..225b584cde04 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:c11c71bfdabd0f5e28d6d8b7539e2a1b7315206fb4df5c2870a658ea9c66c1c6 +# SHA256STAMP:03557959b260db89fed45406e7fae168e0ce9810b47351f22bbd8741a2910898 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 38794dc810ca..7bd924ea5bfc 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..4c96ee38236b 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_int(stmt, 12, 0); + 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/bolt12_wiregen.c b/wire/bolt12_wiregen.c index 58b02e5d2484..a5d1792a25a6 100644 --- a/wire/bolt12_wiregen.c +++ b/wire/bolt12_wiregen.c @@ -1684,4 +1684,4 @@ bool invoice_error_is_valid(const struct tlv_invoice_error *record, size_t *err_ return tlv_fields_valid(record->fields, NULL, err_index); } -// SHA256STAMP:95d5be81bb0846cff337017b812800a19bf176d3182dd605bfe03086c14ef1f4 +// SHA256STAMP:27ffc38bc2be76e159508470734655f35e59d82927beb8c1f62917e592d76d10 diff --git a/wire/bolt12_wiregen.h b/wire/bolt12_wiregen.h index 162cc6aa4a94..0f331da8ad6e 100644 --- a/wire/bolt12_wiregen.h +++ b/wire/bolt12_wiregen.h @@ -323,4 +323,4 @@ struct fallback_address *fromwire_fallback_address(const tal_t *ctx, const u8 ** #endif /* LIGHTNING_WIRE_BOLT12_WIREGEN_H */ -// SHA256STAMP:95d5be81bb0846cff337017b812800a19bf176d3182dd605bfe03086c14ef1f4 +// SHA256STAMP:27ffc38bc2be76e159508470734655f35e59d82927beb8c1f62917e592d76d10 diff --git a/wire/common_wiregen.c b/wire/common_wiregen.c index ef96270784ba..d61d6405eadd 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:20f78b01d36c7db37e7316d8ab52740dd5f39011ea306f0e8b6a5a4a6bbc7c9e +// SHA256STAMP:959a0af7e5dc054bc1bd313dee486b3c2040853b8f3772d889e51048e14ac2b5 diff --git a/wire/common_wiregen.h b/wire/common_wiregen.h index d837aee8c59c..ad19ec882098 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:20f78b01d36c7db37e7316d8ab52740dd5f39011ea306f0e8b6a5a4a6bbc7c9e +// SHA256STAMP:959a0af7e5dc054bc1bd313dee486b3c2040853b8f3772d889e51048e14ac2b5 diff --git a/wire/onion_printgen.c b/wire/onion_printgen.c index 7ae73827ac06..d4d237fb4112 100644 --- a/wire/onion_printgen.c +++ b/wire/onion_printgen.c @@ -859,4 +859,4 @@ void printonion_wire_tlv_message(const char *tlv_name, const u8 *msg) { printwire_tlvs(tlv_name, &msg, &plen, print_tlvs_encmsg_tlvs, ARRAY_SIZE(print_tlvs_encmsg_tlvs)); } } -// SHA256STAMP:aeab913b5da11a9166e167e47d60cd748aa35a8c6c9adc2a7c1f791bed70797f +// SHA256STAMP:fcaea2b057478205299b8935161c994fece0e410e6942503943747625ddcfc8a diff --git a/wire/onion_printgen.h b/wire/onion_printgen.h index 6b85f97d431f..fa2e5b1e44a2 100644 --- a/wire/onion_printgen.h +++ b/wire/onion_printgen.h @@ -58,4 +58,4 @@ void printwire_mpp_timeout(const char *fieldname, const u8 *cursor); void printwire_onionmsg_path(const char *fieldname, const u8 **cursor, size_t *plen); #endif /* LIGHTNING_WIRE_ONION_PRINTGEN_H */ -// SHA256STAMP:aeab913b5da11a9166e167e47d60cd748aa35a8c6c9adc2a7c1f791bed70797f +// SHA256STAMP:fcaea2b057478205299b8935161c994fece0e410e6942503943747625ddcfc8a diff --git a/wire/onion_wiregen.c b/wire/onion_wiregen.c index 8a25fa28dec5..c6b47b0522e0 100644 --- a/wire/onion_wiregen.c +++ b/wire/onion_wiregen.c @@ -1026,4 +1026,4 @@ bool fromwire_mpp_timeout(const void *p) return false; return cursor != NULL; } -// SHA256STAMP:aeab913b5da11a9166e167e47d60cd748aa35a8c6c9adc2a7c1f791bed70797f +// SHA256STAMP:fcaea2b057478205299b8935161c994fece0e410e6942503943747625ddcfc8a diff --git a/wire/onion_wiregen.h b/wire/onion_wiregen.h index 6107b844ec1b..479c89b61041 100644 --- a/wire/onion_wiregen.h +++ b/wire/onion_wiregen.h @@ -317,4 +317,4 @@ bool fromwire_mpp_timeout(const void *p); #endif /* LIGHTNING_WIRE_ONION_WIREGEN_H */ -// SHA256STAMP:aeab913b5da11a9166e167e47d60cd748aa35a8c6c9adc2a7c1f791bed70797f +// SHA256STAMP:fcaea2b057478205299b8935161c994fece0e410e6942503943747625ddcfc8a diff --git a/wire/peer_printgen.c b/wire/peer_printgen.c index e2685809ee8e..6b40e3a0ea32 100644 --- a/wire/peer_printgen.c +++ b/wire/peer_printgen.c @@ -3079,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:4751c4834d5db7d170f8e1ee40ea8b5e12b5552780d37b099fe5fae6f0342c9e +// SHA256STAMP:7c9612ec7cc62b3a44ae65d19b855b521e96796940b4c3d50977d768ace8712e diff --git a/wire/peer_printgen.h b/wire/peer_printgen.h index a3bd3d333fc4..997adc7fc320 100644 --- a/wire/peer_printgen.h +++ b/wire/peer_printgen.h @@ -99,4 +99,4 @@ void printwire_channel_update_checksums(const char *fieldname, const u8 **cursor void printwire_channel_update_timestamps(const char *fieldname, const u8 **cursor, size_t *plen); void printwire_witness_stack(const char *fieldname, const u8 **cursor, size_t *plen); #endif /* LIGHTNING_WIRE_PEER_PRINTGEN_H */ -// SHA256STAMP:4751c4834d5db7d170f8e1ee40ea8b5e12b5552780d37b099fe5fae6f0342c9e +// SHA256STAMP:7c9612ec7cc62b3a44ae65d19b855b521e96796940b4c3d50977d768ace8712e diff --git a/wire/peer_wiregen.c b/wire/peer_wiregen.c index 92c206e9b6c2..5c706df2fc9e 100644 --- a/wire/peer_wiregen.c +++ b/wire/peer_wiregen.c @@ -2484,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:4751c4834d5db7d170f8e1ee40ea8b5e12b5552780d37b099fe5fae6f0342c9e +// SHA256STAMP:7c9612ec7cc62b3a44ae65d19b855b521e96796940b4c3d50977d768ace8712e diff --git a/wire/peer_wiregen.h b/wire/peer_wiregen.h index e063cfb846e2..dc1b44de2af3 100644 --- a/wire/peer_wiregen.h +++ b/wire/peer_wiregen.h @@ -930,4 +930,4 @@ bool fromwire_channel_update_option_channel_htlc_max(const void *p, secp256k1_ec #endif /* LIGHTNING_WIRE_PEER_WIREGEN_H */ -// SHA256STAMP:4751c4834d5db7d170f8e1ee40ea8b5e12b5552780d37b099fe5fae6f0342c9e +// SHA256STAMP:7c9612ec7cc62b3a44ae65d19b855b521e96796940b4c3d50977d768ace8712e From 1e6950b933a20805b43b2c6a60ec463f434f956f Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 22 Jun 2021 16:47:33 -0500 Subject: [PATCH 31/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 ++++++++++++++++++++++---- tests/test_closing.py | 4 ++-- wallet/db_postgres_sqlgen.c | 2 +- wallet/db_sqlite3_sqlgen.c | 2 +- wallet/statements_gettextgen.po | 2 +- wallet/test/run-wallet.c | 6 +++--- 12 files changed, 79 insertions(+), 31 deletions(-) diff --git a/channeld/channeld.c b/channeld/channeld.c index 6e8cef587e9f..410dc74ce76c 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; } @@ -1388,6 +1391,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); @@ -1562,6 +1566,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, @@ -1740,7 +1745,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; @@ -1772,7 +1778,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; } @@ -1829,7 +1836,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 66bf7d957f0e..def355dea902 100644 --- a/channeld/channeld_wire.csv +++ b/channeld/channeld_wire.csv @@ -121,6 +121,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 @@ -135,6 +136,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 @@ -162,6 +164,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 53082063e9db..edfec2ce4b4a 100644 --- a/channeld/channeld_wiregen.c +++ b/channeld/channeld_wiregen.c @@ -490,7 +490,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); @@ -505,6 +505,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++) @@ -516,7 +517,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; @@ -534,6 +535,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 @@ -571,7 +573,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); @@ -583,6 +585,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++) @@ -606,7 +609,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; @@ -621,6 +624,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 @@ -675,7 +679,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); @@ -686,6 +690,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); @@ -704,7 +709,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; @@ -718,6 +723,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; @@ -1175,4 +1181,4 @@ bool fromwire_channeld_blockheight(const void *p, u32 *blockheight) *blockheight = fromwire_u32(&cursor, &plen); return cursor != NULL; } -// SHA256STAMP:40a8d4ea75d57eeddfb5cc648a9ca3e3914dfe500a6054b6a6942f4023a17d82 +// SHA256STAMP:977cf1dac7bbca4163cfbbf53f8f448430775368496205ee6f181eb4d8c8c8af diff --git a/channeld/channeld_wiregen.h b/channeld/channeld_wiregen.h index f53e5e9a4860..e52eafa2019b 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:40a8d4ea75d57eeddfb5cc648a9ca3e3914dfe500a6054b6a6942f4023a17d82 +// SHA256STAMP:977cf1dac7bbca4163cfbbf53f8f448430775368496205ee6f181eb4d8c8c8af diff --git a/common/initial_channel.c b/common/initial_channel.c index f65e6a35d428..2b1cafc98f49 100644 --- a/common/initial_channel.c +++ b/common/initial_channel.c @@ -161,6 +161,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 acbd3149e2ae..40663d17051c 100644 --- a/lightningd/peer_htlcs.c +++ b/lightningd/peer_htlcs.c @@ -1736,6 +1736,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; @@ -1747,9 +1748,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; @@ -1792,6 +1795,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; @@ -1927,6 +1933,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; @@ -1939,6 +1946,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, @@ -1946,7 +1954,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)); @@ -1975,8 +1984,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)); @@ -2011,6 +2021,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)) @@ -2087,6 +2099,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; @@ -2095,10 +2108,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; @@ -2161,6 +2176,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/tests/test_closing.py b/tests/test_closing.py index 4a2f4ba61f5a..f23dbbc394cf 100644 --- a/tests/test_closing.py +++ b/tests/test_closing.py @@ -810,7 +810,7 @@ def test_penalty_htlc_tx_fulfill(node_factory, bitcoind, chainparams): # reconnect with l1, which will fulfill the payment l2.rpc.connect(l1.info['id'], 'localhost', l1.port) - l2.daemon.wait_for_log('got commitsig .*: feerate 11000, 0 added, 1 fulfilled, 0 failed, 0 changed') + l2.daemon.wait_for_log('got commitsig .*: feerate 11000, blockheight: 0, 0 added, 1 fulfilled, 0 failed, 0 changed') l2.daemon.wait_for_log('coins payment_hash: {}'.format(sticky_inv['payment_hash'])) # l2 moves on for closed l3 @@ -966,7 +966,7 @@ def test_penalty_htlc_tx_timeout(node_factory, bitcoind, chainparams): # reconnect with l1, which will fulfill the payment l2.rpc.connect(l1.info['id'], 'localhost', l1.port) - l2.daemon.wait_for_log('got commitsig .*: feerate 11000, 0 added, 1 fulfilled, 0 failed, 0 changed') + l2.daemon.wait_for_log('got commitsig .*: feerate 11000, blockheight: 0, 0 added, 1 fulfilled, 0 failed, 0 changed') l2.daemon.wait_for_log('coins payment_hash: {}'.format(sticky_inv_2['payment_hash'])) # l2 moves on for closed l3 diff --git a/wallet/db_postgres_sqlgen.c b/wallet/db_postgres_sqlgen.c index 5f945e52120a..7c3ce1885f26 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:1778bd4f49bef247c2b4789d1f7db3542fd606cbe186e299738aecbfbb2d44ae +// SHA256STAMP:aa315b69d7586fe52d3f224d87db05201c9582ff9cacdb31b5e94a0287ec7e95 diff --git a/wallet/db_sqlite3_sqlgen.c b/wallet/db_sqlite3_sqlgen.c index 130e28603a64..0be87b79efa8 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:1778bd4f49bef247c2b4789d1f7db3542fd606cbe186e299738aecbfbb2d44ae +// SHA256STAMP:aa315b69d7586fe52d3f224d87db05201c9582ff9cacdb31b5e94a0287ec7e95 diff --git a/wallet/statements_gettextgen.po b/wallet/statements_gettextgen.po index 225b584cde04..84460a8f22a6 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:03557959b260db89fed45406e7fae168e0ce9810b47351f22bbd8741a2910898 +# SHA256STAMP:0867158b98125b1f5cb273f3e8fcc8bcac21f4a8b06032fb86a6ee1c34427ab2 diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 7bd924ea5bfc..ad4d2c04c3e4 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 2493bccfb7190777aeaa3326d3a0264c3160e069 Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 22 Jun 2021 16:49:04 -0500 Subject: [PATCH 32/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 db33e6ec5727..3ab15b23957d 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 3ab59fbf5fe73f18d9b288e588d0e084459e6bad Mon Sep 17 00:00:00 2001 From: niftynei Date: Wed, 23 Jun 2021 14:31:47 -0500 Subject: [PATCH 33/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 | 11 ++----- 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(+), 10 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 1af44a323a95..4e5b8ba26832 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -54,6 +54,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 8371e18fcf12..d66d886fd5d1 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -82,6 +82,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 7ded49c9bd4e..beef3952297f 100644 --- a/doc/lightning-feerates.7 +++ b/doc/lightning-feerates.7 @@ -16,7 +16,6 @@ C-lightning will also smoothen feerate estimations from the backend\. \fIstyle\fR is either of the two strings: - .RS .IP \[bu] \fIperkw\fR - provide feerate in units of satoshis per 1000 weight\. @@ -27,7 +26,6 @@ C-lightning will also smoothen feerate estimations from the backend\. Bitcoin transactions have non-witness and witness bytes: - .RS .IP \[bu] Non-witness bytes count as 4 weight, 1 virtual byte\. @@ -58,7 +56,6 @@ which will override the recommended feerates returned by \fBfeerates\fR\. On success, an object is returned, containing: - .RS .IP \[bu] \fBperkb\fR (object, optional): If \fIstyle\fR parameter was perkb: @@ -125,7 +122,6 @@ On success, an object is returned, containing: The following warnings may also be returned: - .RS .IP \[bu] \fBwarning_missing_feerates\fR: Some fee estimates are missing @@ -143,7 +139,6 @@ Many other commands have a \fIfeerate\fR parameter, which can be the strings \fIurgent\fR, \fInormal\fR, or \fIslow\fR\. These are mapped to the \fBfeerates\fR outputs as: - .RS .IP \[bu] \fIurgent\fR - equal to \fIunilateral_close\fR @@ -167,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:227e0f9f9b4d3c2b80d58466ed4fae768a5a2e7c2234e43105e21efc4a0b1861 +\" SHA256STAMP:3c68e2e2b47bc4107d71e263372b3ec3ac77434d7319c670f293d3be88703fe7 diff --git a/doc/lightning-feerates.7.md b/doc/lightning-feerates.7.md index 50cc43c5f67c..0cd49794b6b2 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..69a7c3adf45c --- /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:1395d3fe85f6eb1f09c3706c50a9660dd9ade04e71435bde3fe1f9660f7b2655 diff --git a/doc/lightning-parsefeerate.7.md b/doc/lightning-parsefeerate.7.md new file mode 100644 index 000000000000..6c649f7518b1 --- /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:db3351466f8d2675cecf6f5909c1f3ff264b6ffa865b2d64eb02bf0b45a31a4d) 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 1b24d5e7e68d..44ff94e887b2 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -1462,6 +1462,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') @@ -1539,6 +1544,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 484bcbefd0ec1d88f37c80290ee59efc67eb4772 Mon Sep 17 00:00:00 2001 From: niftynei Date: Fri, 2 Jul 2021 14:46:20 -0500 Subject: [PATCH 34/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 7d756e01b757bd04229b18455e0e0ca8afae6b6b Mon Sep 17 00:00:00 2001 From: niftynei Date: Fri, 2 Jul 2021 14:54:40 -0500 Subject: [PATCH 35/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 b8656a6c6a1b..91ca990a9178 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:40630b923c5c303627b75b8ca663b0d8a060039d2171571f6ecab580695dfdba +// SHA256STAMP:5aa638efffb78c0f1cac4889fb37e3666792ad716f7db66c925b4640628ffbde diff --git a/onchaind/onchaind_wiregen.h b/onchaind/onchaind_wiregen.h index 7f9de0d68d0a..e8a4d758935b 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:40630b923c5c303627b75b8ca663b0d8a060039d2171571f6ecab580695dfdba +// SHA256STAMP:5aa638efffb78c0f1cac4889fb37e3666792ad716f7db66c925b4640628ffbde 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 7c3ce1885f26..af2c44b92bc1 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:aa315b69d7586fe52d3f224d87db05201c9582ff9cacdb31b5e94a0287ec7e95 +// SHA256STAMP:ee6c1b38b43e1959bbd7b31e15afa4a45bcbd37acf7ce6ffc994cc8002ec96e1 diff --git a/wallet/db_sqlite3_sqlgen.c b/wallet/db_sqlite3_sqlgen.c index 0be87b79efa8..5723e5460e9a 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:aa315b69d7586fe52d3f224d87db05201c9582ff9cacdb31b5e94a0287ec7e95 +// SHA256STAMP:ee6c1b38b43e1959bbd7b31e15afa4a45bcbd37acf7ce6ffc994cc8002ec96e1 diff --git a/wallet/reservation.c b/wallet/reservation.c index db16cfc86d26..539a57369528 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 84460a8f22a6..70379d540984 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:0867158b98125b1f5cb273f3e8fcc8bcac21f4a8b06032fb86a6ee1c34427ab2 +# SHA256STAMP:8f553a6c38a1b4080ab33ce6fa902657bf4bf40dd7b5308ba0354f387ce48c95 diff --git a/wallet/wallet.c b/wallet/wallet.c index 4c96ee38236b..a12d73953708 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 96f33e7cb41e..fbd0dabe6dc3 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 4ff926ac0b5f979958e081abbc44413ee6beb847 Mon Sep 17 00:00:00 2001 From: niftynei Date: Fri, 2 Jul 2021 14:56:35 -0500 Subject: [PATCH 36/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.c | 1 - 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 +- 7 files changed, 151 insertions(+), 122 deletions(-) diff --git a/common/utxo.c b/common/utxo.c index 22777320555c..09ad55b734ce 100644 --- a/common/utxo.c +++ b/common/utxo.c @@ -1,5 +1,4 @@ #include "config.h" -#include #include #include #include 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 af2c44b92bc1..7dd27da86f53 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:ee6c1b38b43e1959bbd7b31e15afa4a45bcbd37acf7ce6ffc994cc8002ec96e1 +// SHA256STAMP:020ef91a3637bbe29c82477083389a5ecaf359ae049940017ec5c76609c08fdc diff --git a/wallet/db_sqlite3_sqlgen.c b/wallet/db_sqlite3_sqlgen.c index 5723e5460e9a..7ccdabf77598 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:ee6c1b38b43e1959bbd7b31e15afa4a45bcbd37acf7ce6ffc994cc8002ec96e1 +// SHA256STAMP:020ef91a3637bbe29c82477083389a5ecaf359ae049940017ec5c76609c08fdc diff --git a/wallet/reservation.c b/wallet/reservation.c index 539a57369528..4b754b6ef40b 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 70379d540984..ec0d7c660e17 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:8f553a6c38a1b4080ab33ce6fa902657bf4bf40dd7b5308ba0354f387ce48c95 +# SHA256STAMP:c273019025094b8ac8311eb7a8489207006506ca46a1963c5924e1947e4c60d5 diff --git a/wallet/wallet.c b/wallet/wallet.c index a12d73953708..e9a26b611cee 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 27657cf49b4407c548cf4e8f39493dc4009ddd29 Mon Sep 17 00:00:00 2001 From: niftynei Date: Fri, 2 Jul 2021 15:21:54 -0500 Subject: [PATCH 37/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 02d0f4b42db1..18c47e82ab48 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -773,6 +773,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 9c39e6acfdb2b1b8a8eefc0d0a4b19137ff9bc75 Mon Sep 17 00:00:00 2001 From: niftynei Date: Fri, 2 Jul 2021 15:25:40 -0500 Subject: [PATCH 38/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 18c47e82ab48..de95ef90f716 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 8097937c47de2e1bcab9b71b0966fa05dc3d79a6 Mon Sep 17 00:00:00 2001 From: niftynei Date: Fri, 2 Jul 2021 15:38:59 -0500 Subject: [PATCH 39/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 410dc74ce76c..6b08faca808c 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -1997,6 +1997,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 74bf559385b5..4f3a4549f55f 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 40a770203762..6f8c2837a20f 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 @@ -67,6 +67,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\. @@ -123,4 +128,4 @@ ZmnSCPxj \fI is mainly responsible\. Main web site: \fIhttps://github.com/ElementsProject/lightning\fR -\" SHA256STAMP:03f1e6937a88aad4bdcd29d010da9ced148e3498ea19b388e8cbfde25276482d +\" SHA256STAMP:c36a8ba48c3d2826344e23f880c21e0183942df8523da94394e5786dec874083 diff --git a/doc/lightning-close.7.md b/doc/lightning-close.7.md index 2e42891015a0..4d9ab13225b4 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 ----------- @@ -56,6 +56,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 b0aaf76ae38c..b8566946f589 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -1671,7 +1671,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; @@ -1685,6 +1685,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(); @@ -1714,6 +1716,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 74ccf750bcf1cbd7a4c5491dcdae31ce5654f007 Mon Sep 17 00:00:00 2001 From: niftynei Date: Fri, 2 Jul 2021 15:54:03 -0500 Subject: [PATCH 40/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 6b08faca808c..438de3c202aa 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -2364,9 +2364,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 @@ -2442,11 +2445,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 8666cbbe27d89286779a9433e300d47f98cbc585 Mon Sep 17 00:00:00 2001 From: niftynei Date: Fri, 2 Jul 2021 16:00:17 -0500 Subject: [PATCH 41/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 4c598dade344..9361b1cc4c5d 100644 --- a/common/json_tok.c +++ b/common/json_tok.c @@ -654,3 +654,19 @@ param_routehint_array(struct command *cmd, const char *name, const char *buffer, } 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 4b57e9bebdfe..74dbf58a68ac 100644 --- a/common/json_tok.h +++ b/common/json_tok.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -204,4 +205,12 @@ struct command_result * param_routehint_array(struct command *cmd, const char *name, const char *buffer, const jsmntok_t *tok, struct route_info ***ris); +/** + * 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 27a6cabcd7ce..f166d4c0e421 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 e2ca8871d4e4..f14a66b53825 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, u64 *allow_extra UNNEEDED, size_t *err_index UNNEEDED) 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 778d13b89be1..f9ec59a4045b 100644 --- a/plugins/Makefile +++ b/plugins/Makefile @@ -94,7 +94,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 \ @@ -133,6 +135,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 85fbd28cfbdba875b9a80c9146351c32e778ed2e Mon Sep 17 00:00:00 2001 From: niftynei Date: Fri, 2 Jul 2021 16:19:47 -0500 Subject: [PATCH 42/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 | 1 + 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 +++- plugins/topology.c | 5 ++++ 19 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 4f3a4549f55f..8dc39f6116a0 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 3180e88b8693..d6177b742beb 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:c7cd9291a08e66e41b24d0045c313ac1e3dabcb4579ab5fe132aad8d1ecbb640 +\" SHA256STAMP:73f87ce2618c7be8bce775de6e879f88a26e7b2cc48bedb077c29dba725d24eb diff --git a/doc/lightning-fundchannel.7.md b/doc/lightning-fundchannel.7.md index 125fc92048cf..30039a88f670 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 c86e9ea5570d..361d874ac537 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 @@ -208,4 +212,4 @@ ZmnSCPxj \fI is mainly responsible\. Main web site: \fIhttps://github.com/ElementsProject/lightning\fR -\" SHA256STAMP:fa55ac01a568d6b816641ddbfa3c9cccf437dea06df5ec84747f7ef02db6d47e +\" SHA256STAMP:a01cd5e8fa80e29fac6a23bc2907207a59714455b15435d4152b999f82da173b diff --git a/doc/lightning-multifundchannel.7.md b/doc/lightning-multifundchannel.7.md index a0472f9d4db7..d99e3e0fdfca 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 3c449a82283c..9ffdef4764ff 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 @@ -119,4 +124,4 @@ lightning-fundchannel_\fBcomplete\fR(7), \fBlightning-fundchannel\fR(7), Main web site: \fIhttps://github.com/ElementsProject/lightning\fR -\" SHA256STAMP:13023bb80ee4a7f6a94a168399a01e05c6c5ab68e9eec5795ebd5f49207a03ac +\" SHA256STAMP:a5532a84325f6807aa370bd34a12828dba2fd87bd348bdeaac4217518882d90c diff --git a/doc/lightning-openchannel_init.7.md b/doc/lightning-openchannel_init.7.md index b3493557f852..0b7ae285c548 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 34fd7d5ba6f5..44f7e7fcd4e4 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)); } @@ -2597,7 +2601,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); @@ -2619,6 +2624,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; @@ -2631,9 +2637,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); @@ -2754,7 +2766,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 acb0e851c5f4..b783621d06ab 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 4bf1dee01a07..cf7492ea7fc9 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -2598,6 +2598,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, @@ -2609,7 +2610,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; @@ -2747,6 +2749,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: @@ -2756,6 +2775,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 823b790ef4a0..8dffaef932f9 100644 --- a/openingd/dualopend_wire.csv +++ b/openingd/dualopend_wire.csv @@ -95,6 +95,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 54083001c7c8..605e51e2c454 100644 --- a/openingd/dualopend_wiregen.c +++ b/openingd/dualopend_wiregen.c @@ -338,6 +338,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 { @@ -362,7 +363,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:65d1bedd1e05436c5474d298811fbb9c3fc96ac4e84bef8081c4eee55de286ad +// SHA256STAMP:893f2d8e99ee42b814c293ee5fc24c6234b4198c87eaa9ec55e83c8085b5045f diff --git a/openingd/dualopend_wiregen.h b/openingd/dualopend_wiregen.h index efbfb40d2054..c4f693f21b98 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:65d1bedd1e05436c5474d298811fbb9c3fc96ac4e84bef8081c4eee55de286ad +// SHA256STAMP:893f2d8e99ee42b814c293ee5fc24c6234b4198c87eaa9ec55e83c8085b5045f 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); } diff --git a/plugins/topology.c b/plugins/topology.c index 9a263df64ea0..c58dfb219dda 100644 --- a/plugins/topology.c +++ b/plugins/topology.c @@ -561,6 +561,11 @@ static void json_add_node(struct json_stream *js, if (na_tlvs->option_will_fund) { json_object_start(js, "option_will_fund"); json_add_lease_rates(js, na_tlvs->option_will_fund); + /* As a convenience, add a hexstring version + * of this info */ + json_add_string(js, "compact_lease", + lease_rates_tohex(tmpctx, + na_tlvs->option_will_fund)); json_object_end(js); } } From 93854d590a27b0f912c07c7a4a14faf3874a8816 Mon Sep 17 00:00:00 2001 From: niftynei Date: Fri, 2 Jul 2021 16:38:04 -0500 Subject: [PATCH 43/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 6e7b36b7766d7218005b03f7d422cb20adab16ec Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 6 Jul 2021 12:17:51 -0500 Subject: [PATCH 44/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 +++++++++++++ tests/test_opening.py | 6 ++---- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/openingd/dualopend.c b/openingd/dualopend.c index cf7492ea7fc9..4bdfe4ae23da 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -2050,7 +2050,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; diff --git a/tests/test_opening.py b/tests/test_opening.py index c38e4eb3a647..dbb239a5e8de 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -26,10 +26,8 @@ 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) - 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.queryrates(l2.info['id'], amount, amount * 10) l2.rpc.call('funderupdate', {'policy': 'match', 'policy_mod': 100, From 02644be4e9736124c639823fa43d5f91e8a4dcff Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 6 Jul 2021 12:19:34 -0500 Subject: [PATCH 45/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 4bdfe4ae23da..a8ae795acb78 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -790,8 +790,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: ... @@ -804,7 +815,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 1d6f313d9763f432cf9e8bda38e88b7df7cb937a Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 6 Jul 2021 12:21:43 -0500 Subject: [PATCH 46/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 a8ae795acb78..f9fac96304c2 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -2027,7 +2027,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; @@ -2175,6 +2175,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, + tx_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)) @@ -2253,7 +2297,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, @@ -2276,47 +2321,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, - tx_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 64123f15e4f4a307c20076bffeeeeb43003e3440 Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 6 Jul 2021 12:25:24 -0500 Subject: [PATCH 47/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 f9fac96304c2..b57f976ee6bb 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -2633,7 +2633,7 @@ static void opener_start(struct state *state, u8 *msg) state->our_role = TX_INITIATOR; tx_state->tx_locktime = tx_state->psbt->tx->locktime; - 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 86dacd942cb2b9e23940820c88cc2026a23dd9e4 Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 6 Jul 2021 12:27:06 -0500 Subject: [PATCH 48/56] lease-channels: tests for the test gods Check that channel leases work as expected for unilateral closes and cheats! --- tests/test_closing.py | 373 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 373 insertions(+) diff --git a/tests/test_closing.py b/tests/test_closing.py index f23dbbc394cf..bf21a5a64ada 100644 --- a/tests/test_closing.py +++ b/tests/test_closing.py @@ -718,6 +718,379 @@ 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_post_expiry(node_factory, bitcoind): + + opts = {'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) + + feerate = 2000 + amount = 500000 + l1.fundwallet(20000000) + l2.fundwallet(20000000) + + # l1 leases a channel from l2 + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + 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.rpc.fundchannel(l2.info['id'], amount, request_amt=amount, + feerate='{}perkw'.format(feerate), + 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'] + assert Millisatoshi(est_fees + amount * 1000) == Millisatoshi(fundings['remote_msat']) + + 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]) + + # send some payments, mine a block or two + inv = l2.rpc.invoice(10**4, '1', 'no_1') + l1.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(l1.get_channel_scid(l2)) + + bitcoind.generate_block(6) + sync_blockheight(bitcoind, [l1, l2]) + # 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 115') + + # We need to give l1-l2 time to update their blockheights + bitcoind.generate_block(1000) + sync_blockheight(bitcoind, [l1, l2]) + l1.daemon.wait_for_log('peer_out WIRE_UPDATE_BLOCKHEIGHT') + + bitcoind.generate_block(1000) + sync_blockheight(bitcoind, [l1, l2]) + l1.daemon.wait_for_log('peer_out WIRE_UPDATE_BLOCKHEIGHT') + + bitcoind.generate_block(1000) + sync_blockheight(bitcoind, [l1, l2]) + l1.daemon.wait_for_log('peer_out WIRE_UPDATE_BLOCKHEIGHT') + + bitcoind.generate_block(1000) + sync_blockheight(bitcoind, [l1, l2]) + l1.daemon.wait_for_log('peer_out WIRE_UPDATE_BLOCKHEIGHT') + + bitcoind.generate_block(32) + sync_blockheight(bitcoind, [l1, l2]) + l1.daemon.wait_for_log('peer_out WIRE_UPDATE_BLOCKHEIGHT') + + # l1<->l2 mutual close should work + chan = l1.get_channel_scid(l2) + l2.rpc.connect(l1.info['id'], 'localhost', l1.port) + l1.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') +@pytest.mark.slow_test +@pytest.mark.developer("requres 'dev-queryrates'") +def test_channel_lease_unilat_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 + ''' + opts = {'funder-policy': 'match', 'funder-policy-mod': 100, + 'lease-fee-base-msat': '100sat', 'lease-fee-basis': 100} + + l1, l2, l3 = node_factory.get_nodes(3, opts=opts) + # Allow l2 some warnings + l2.allow_warning = True + + feerate = 2000 + amount = 500000 + l1.fundwallet(20000000) + l2.fundwallet(20000000) + l3.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']) + + # 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'] + assert Millisatoshi(est_fees + amount * 1000) == Millisatoshi(fundings['remote_msat']) + + bitcoind.generate_block(6) + l1.daemon.wait_for_log('to CHANNELD_NORMAL') + l3.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]) + + # 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']) + + bitcoind.generate_block(6) + sync_blockheight(bitcoind, [l1, l2, l3]) + # 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 110') + 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]) + + bitcoind.generate_block(4032) + sync_blockheight(bitcoind, [l2, l3]) + + 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') + + +@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(wait_for_bitcoind_sync=True) + l1.rpc.connect(l2.info['id'], 'localhost', l2.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 8729d6b0676db93bc89a54742081b76520cb7e84 Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 6 Jul 2021 13:48:35 -0500 Subject: [PATCH 49/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/startup_regtest.sh | 2 +- lightningd/dual_open_control.c | 207 +++++++++++++++++---------------- tests/test_closing.py | 14 ++- tests/test_opening.py | 5 +- 4 files changed, 118 insertions(+), 110 deletions(-) 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 44f7e7fcd4e4..20c861604c6f 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -2509,106 +2509,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, @@ -3135,14 +3035,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", @@ -3181,7 +3185,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 bf21a5a64ada..737f21f396fc 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 @@ -768,6 +769,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.developer("requres 'dev-queryrates'") @pytest.mark.slow_test def test_channel_lease_post_expiry(node_factory, bitcoind): @@ -868,7 +870,7 @@ def test_channel_lease_unilat_closes(node_factory, bitcoind): l3.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 @@ -878,7 +880,7 @@ def test_channel_lease_unilat_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, @@ -949,6 +951,7 @@ def test_channel_lease_unilat_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 @@ -966,7 +969,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 @@ -1021,6 +1024,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 @@ -1038,7 +1042,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 dbb239a5e8de..6bbda4c8c3ae 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) @@ -27,7 +28,7 @@ def test_queryrates(node_factory, bitcoind): l1.rpc.connect(l2.info['id'], 'localhost', l2.port) with pytest.raises(RpcError, match=r'not advertising liquidity'): - l1.rpc.queryrates(l2.info['id'], amount, amount * 10) + l1.rpc.dev_queryrates(l2.info['id'], amount, amount * 10) l2.rpc.call('funderupdate', {'policy': 'match', 'policy_mod': 100, @@ -40,7 +41,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 7049c30fb71ae342fd0deaaff8f8b0be6196e6af Mon Sep 17 00:00:00 2001 From: niftynei Date: Wed, 7 Jul 2021 15:51:51 -0500 Subject: [PATCH 50/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 b57f976ee6bb..24995a7b1a59 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -3483,7 +3483,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: @@ -3534,6 +3534,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 48a46a3ae1a483c6215f3a0e6a2972c474c05918 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sun, 11 Jul 2021 16:29:42 +0930 Subject: [PATCH 51/56] overflows: helpers for integer assignment overflows. Signed-off-by: Rusty Russell --- common/overflows.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/common/overflows.h b/common/overflows.h index b649532efcdf..117de580a138 100644 --- a/common/overflows.h +++ b/common/overflows.h @@ -1,6 +1,7 @@ #ifndef LIGHTNING_COMMON_OVERFLOWS_H #define LIGHTNING_COMMON_OVERFLOWS_H #include "config.h" +#include static inline bool add_overflows_size_t(uint64_t a, uint64_t b) { @@ -21,4 +22,22 @@ static inline bool mul_overflows_u64(uint64_t a, uint64_t b) ret = a * b; return (ret / a != b); } + +static inline bool assign_overflow_u8(u8 *dst, uint64_t v) +{ + *dst = v; + return *dst == v; +} + +static inline bool assign_overflow_u16(u16 *dst, uint64_t v) +{ + *dst = v; + return *dst == v; +} + +static inline bool assign_overflow_u32(u32 *dst, uint64_t v) +{ + *dst = v; + return *dst == v; +} #endif /* LIGHTNING_COMMON_OVERFLOWS_H */ From 26474c742d2cbc2212096130e3f69f5b12cd41c8 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sun, 11 Jul 2021 16:29:42 +0930 Subject: [PATCH 52/56] lease_rates, funder: use overflow helpers Signed-off-by: Rusty Russell --- common/lease_rates.c | 9 ++--- plugins/funder.c | 84 ++++++++++++++++---------------------------- 2 files changed, 36 insertions(+), 57 deletions(-) diff --git a/common/lease_rates.c b/common/lease_rates.c index 4ab08c9d2691..118269ad51f5 100644 --- a/common/lease_rates.c +++ b/common/lease_rates.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -102,15 +103,15 @@ bool lease_rates_calc_fee(struct lease_rates *rates, 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 */ + return assign_overflow_u32(&rates->channel_fee_max_base_msat, + amt.millisatoshis); /* Raw: conversion */ } 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 */ + return assign_overflow_u32(&rates->lease_fee_base_sat, + amt.satoshis); /* Raw: conversion */ } char *lease_rates_tohex(const tal_t *ctx, const struct lease_rates *rates) diff --git a/plugins/funder.c b/plugins/funder.c index 9dbbba5a4bf5..fed510d3eb93 100644 --- a/plugins/funder.c +++ b/plugins/funder.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -832,7 +833,7 @@ parse_lease_rates(struct command *cmd, const char *buffer, u32 *lease_fee_basis, struct amount_sat *lease_fee_sats, u32 *funding_weight, - u32 *chan_fee_ppt, + u32 *channel_fee_max_proportional_thousandths, struct amount_msat *chan_fee_msats) { @@ -843,59 +844,37 @@ parse_lease_rates(struct command *cmd, const char *buffer, else if (lease_fee_basis || lease_fee_sats || funding_weight - || chan_fee_ppt + || channel_fee_max_proportional_thousandths || 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"); + /* Sometimes a local macro is neater than the alternative */ +#define ASSIGN_OR_RETURN_FAIL(type, member) \ + do { \ + if (member && \ + !assign_overflow_##type(&policy->rates->member, *member)) \ + return command_fail_badparam(cmd, #member, \ + buffer, tok, "overflow"); \ +} while(0) + + ASSIGN_OR_RETURN_FAIL(u16, lease_fee_basis); + ASSIGN_OR_RETURN_FAIL(u16, funding_weight); + ASSIGN_OR_RETURN_FAIL(u16, channel_fee_max_proportional_thousandths); +#undef ASSIGN_OR_RETURN_FAIL + + if (chan_fee_msats + && !assign_overflow_u32(&policy->rates->channel_fee_max_base_msat, + chan_fee_msats->millisatoshis /* Raw: conversion */)) { + return command_fail_badparam(cmd, "channel_fee_max_base_msat", + 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"); + if (lease_fee_sats + && !assign_overflow_u32(&policy->rates->lease_fee_base_sat, + lease_fee_sats->satoshis /* Raw: conversion */)) { + return command_fail_badparam(cmd, "lease_fee_base_sat", + buffer, tok, "overflow"); } return NULL; @@ -1126,9 +1105,8 @@ static char *option_channel_base(const char *arg, struct funder_policy *policy) 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 */ + if (!assign_overflow_u32(&policy->rates->channel_fee_max_base_msat, + amt.millisatoshis)) /* Raw: conversion */ return tal_fmt(NULL, "channel_fee_max_base_msat overflowed"); return NULL; @@ -1163,8 +1141,8 @@ static char *option_lease_fee_base(const char *arg, 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 */ + if (!assign_overflow_u32(&policy->rates->lease_fee_base_sat, + amt.satoshis)) /* Raw: conversion */ return tal_fmt(NULL, "lease_fee_base_sat overflowed"); return NULL; From 4a967bac76c6692df045e548cba209e06debe9bb Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sun, 11 Jul 2021 16:29:42 +0930 Subject: [PATCH 53/56] gossipd: de-duplicate code. Signed-off-by: Rusty Russell --- gossipd/gossip_generation.c | 79 +++++++------------------------------ 1 file changed, 14 insertions(+), 65 deletions(-) diff --git a/gossipd/gossip_generation.c b/gossipd/gossip_generation.c index 35c6b83f269e..a90178616754 100644 --- a/gossipd/gossip_generation.c +++ b/gossipd/gossip_generation.c @@ -211,66 +211,15 @@ static void sign_and_send_nannounce(struct daemon *daemon, tal_hex(tmpctx, err)); } + +/* Mutual recursion via timer */ +static void update_own_node_announcement_after_startup(struct daemon *daemon); + /* 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 * (to prevent spam), so we only call this once we've announced a channel. */ -static void update_own_node_announcement(struct daemon *daemon) -{ - u32 timestamp = gossip_time_now(daemon->rstate).ts.tv_sec; - u8 *nannounce; - struct node *self = get_node(daemon->rstate, &daemon->id); - - /* Discard existing timer. */ - daemon->node_announce_timer = tal_free(daemon->node_announce_timer); - - /* 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; - - if (!nannounce_different(daemon->rstate->gs, self, nannounce, - NULL)) - 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); -} - -static void update_own_node_announce_startup(struct daemon *daemon) +static void update_own_node_announcement(struct daemon *daemon, bool startup) { u32 timestamp = gossip_time_now(daemon->rstate).ts.tv_sec; u8 *nannounce; @@ -290,7 +239,6 @@ static void update_own_node_announce_startup(struct daemon *daemon) timestamp, daemon->rates); - /* If it's the same as the previous, nothing to do. */ if (self && self->bcast.index) { u32 next; @@ -301,7 +249,7 @@ static void update_own_node_announce_startup(struct daemon *daemon) return; /* Missing liquidity_ad, maybe we'll get plugin callback */ - if (only_missing_tlv) { + if (startup && only_missing_tlv) { u32 delay = GOSSIP_NANN_STARTUP_DELAY(daemon->rstate->dev_fast_gossip); status_debug("node_announcement: delaying" " %u secs at start", delay); @@ -310,11 +258,10 @@ static void update_own_node_announce_startup(struct daemon *daemon) = new_reltimer(&daemon->timers, daemon, time_from_sec(delay), - update_own_node_announcement, + update_own_node_announcement_after_startup, daemon); return; } - /* BOLT #7: * * The origin node: @@ -333,7 +280,7 @@ static void update_own_node_announce_startup(struct daemon *daemon) = new_reltimer(&daemon->timers, daemon, time_from_sec(next - timestamp), - update_own_node_announcement, + update_own_node_announcement_after_startup, daemon); return; } @@ -342,6 +289,11 @@ static void update_own_node_announce_startup(struct daemon *daemon) sign_and_send_nannounce(daemon, nannounce, timestamp); } +static void update_own_node_announcement_after_startup(struct daemon *daemon) +{ + update_own_node_announcement(daemon, false); +} + /* Should we announce our own node? Called at strategic places. */ void maybe_send_own_node_announce(struct daemon *daemon, bool startup) { @@ -352,10 +304,7 @@ void maybe_send_own_node_announce(struct daemon *daemon, bool startup) if (!daemon->rstate->local_channel_announced) return; - if (startup) - update_own_node_announce_startup(daemon); - else - update_own_node_announcement(daemon); + update_own_node_announcement(daemon, startup); } /* Our timer callbacks take a single argument, so we marshall everything From f8f4e430ab3411f296f6bd799f2c1974ba895390 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sun, 11 Jul 2021 16:29:42 +0930 Subject: [PATCH 54/56] lease_rates: lease_rates_eq. We don't actually use the NULL-is-equal in the one caller, so ignore that. Signed-off-by: Rusty Russell --- common/lease_rates.c | 29 ++++------------------------- common/lease_rates.h | 12 +++++++++--- 2 files changed, 13 insertions(+), 28 deletions(-) diff --git a/common/lease_rates.c b/common/lease_rates.c index 118269ad51f5..fb05d454e2d6 100644 --- a/common/lease_rates.c +++ b/common/lease_rates.c @@ -7,36 +7,15 @@ #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) +bool lease_rates_empty(const struct lease_rates *rates) { + /* static means it's zero initialized */ + static const struct lease_rates zero; 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; + return lease_rates_eq(rates, &zero); } void lease_rates_get_commitment(struct pubkey *pubkey, diff --git a/common/lease_rates.h b/common/lease_rates.h index d6e8b5afbf1c..3b70a83428b0 100644 --- a/common/lease_rates.h +++ b/common/lease_rates.h @@ -2,6 +2,7 @@ #define LIGHTNING_COMMON_LEASE_RATES_H #include "config.h" #include +#include struct amount_msat; struct amount_sat; @@ -11,7 +12,7 @@ struct sha256; #define LEASE_RATE_DURATION 4032 -bool lease_rates_empty(struct lease_rates *rates); +bool lease_rates_empty(const struct lease_rates *rates); void lease_rates_get_commitment(struct pubkey *pubkey, u32 lease_expiry, @@ -19,8 +20,13 @@ 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); +/* lease_rates_eq: has 2 padding bytes after third field */ +STRUCTEQ_DEF(lease_rates, 2, + funding_weight, + lease_fee_basis, + channel_fee_max_proportional_thousandths, + lease_fee_base_sat, + channel_fee_max_base_msat); bool lease_rates_calc_fee(struct lease_rates *rates, struct amount_sat accept_funding_sats, From 103d3f1af73fa2d637c607cbea48ca2d6823a779 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sun, 11 Jul 2021 16:29:42 +0930 Subject: [PATCH 55/56] common/lease_rates: more things const. And fix up lease_rates_fromhex to be the obvious calling convention. Signed-off-by: Rusty Russell --- common/json_tok.c | 6 +++--- common/lease_rates.c | 22 ++++++++++------------ common/lease_rates.h | 9 ++++----- 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/common/json_tok.c b/common/json_tok.c index 9361b1cc4c5d..dd4ace1aec94 100644 --- a/common/json_tok.c +++ b/common/json_tok.c @@ -661,9 +661,9 @@ struct command_result *param_lease_hex(struct command *cmd, const jsmntok_t *tok, struct lease_rates **rates) { - if (!lease_rates_fromhex(cmd, buffer + tok->start, - tok->end - tok->start, - rates)) + *rates = lease_rates_fromhex(cmd, buffer + tok->start, + tok->end - tok->start); + if (!*rates) return command_fail(cmd, JSONRPC2_INVALID_PARAMS, "Could not decode '%s' %.*s", name, json_tok_full_len(tok), diff --git a/common/lease_rates.c b/common/lease_rates.c index fb05d454e2d6..8aab58eda440 100644 --- a/common/lease_rates.c +++ b/common/lease_rates.c @@ -18,7 +18,7 @@ bool lease_rates_empty(const struct lease_rates *rates) return lease_rates_eq(rates, &zero); } -void lease_rates_get_commitment(struct pubkey *pubkey, +void lease_rates_get_commitment(const struct pubkey *pubkey, u32 lease_expiry, u32 chan_fee_msat, u16 chan_fee_ppt, @@ -44,7 +44,7 @@ void lease_rates_get_commitment(struct pubkey *pubkey, sha256_done(&sctx, sha); } -bool lease_rates_calc_fee(struct lease_rates *rates, +bool lease_rates_calc_fee(const struct lease_rates *rates, struct amount_sat accept_funding_sats, struct amount_sat requested_sats, u32 onchain_feerate, @@ -103,22 +103,20 @@ char *lease_rates_tohex(const tal_t *ctx, const struct lease_rates *rates) return hex; } -bool lease_rates_fromhex(const tal_t *ctx, - const char *hexdata, size_t hexlen, - struct lease_rates **rates) +struct lease_rates *lease_rates_fromhex(const tal_t *ctx, + const char *hexdata, size_t hexlen) { const u8 *data = tal_hexdata(ctx, hexdata, hexlen); size_t len = tal_bytelen(data); + struct lease_rates *ret; - *rates = tal(ctx, struct lease_rates); - fromwire_lease_rates(&data, &len, *rates); + ret = tal(ctx, struct lease_rates); + fromwire_lease_rates(&data, &len, ret); - if (data == NULL) { - tal_free(*rates); - return false; - } + if (data == NULL || len != 0) + return tal_free(ret); - return true; + return ret; } char *lease_rates_fmt(const tal_t *ctx, const struct lease_rates *rates) diff --git a/common/lease_rates.h b/common/lease_rates.h index 3b70a83428b0..14bc947e7e71 100644 --- a/common/lease_rates.h +++ b/common/lease_rates.h @@ -14,7 +14,7 @@ struct sha256; bool lease_rates_empty(const struct lease_rates *rates); -void lease_rates_get_commitment(struct pubkey *pubkey, +void lease_rates_get_commitment(const struct pubkey *pubkey, u32 lease_expiry, u32 chan_fee_msat, u16 chan_fee_ppt, @@ -28,7 +28,7 @@ STRUCTEQ_DEF(lease_rates, 2, lease_fee_base_sat, channel_fee_max_base_msat); -bool lease_rates_calc_fee(struct lease_rates *rates, +bool lease_rates_calc_fee(const struct lease_rates *rates, struct amount_sat accept_funding_sats, struct amount_sat requested_sats, u32 onchain_feerate, @@ -42,9 +42,8 @@ WARN_UNUSED_RESULT bool lease_rates_set_lease_fee_sat(struct lease_rates *rates, 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); +struct lease_rates *lease_rates_fromhex(const tal_t *ctx, + const char *hexdata, size_t len); /* Format a string describing the passed in lease_rates */ char *lease_rates_fmt(const tal_t *ctx, const struct lease_rates *rates); From 7be8e71ca2b995313a8eba3156bf625a469fd762 Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 20 Jul 2021 11:00:18 -0500 Subject: [PATCH 56/56] printlogs for failing tests --- tests/test_misc.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/test_misc.py b/tests/test_misc.py index 44ff94e887b2..c78d250e4b1d 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -1154,6 +1154,12 @@ def test_blockchaintrack(node_factory, bitcoind): assert [o for o in l1.rpc.listfunds()['outputs'] if o['status'] != "unconfirmed"] == [] +def chan_active(node, scid, is_active): + chans = node.rpc.listchannels(scid)['channels'] + print(chans) + return [c['active'] for c in chans] == [is_active, is_active] + + @pytest.mark.developer("needs DEVELOPER=1") @pytest.mark.openchannel('v2') @pytest.mark.openchannel('v1') @@ -1189,8 +1195,8 @@ def test_funding_reorg_private(node_factory, bitcoind): l2.daemon.wait_for_logs([r'Removing stale block {}'.format(106), r'Got depth change .->{} for .* REORG'.format(0)]) - wait_for(lambda: [c['active'] for c in l2.rpc.listchannels('106x1x0')['channels']] == [False, False]) - wait_for(lambda: [c['active'] for c in l2.rpc.listchannels('108x1x0')['channels']] == [True, True]) + wait_for(lambda: chan_active(l2, '106x1x0', False)) + wait_for(lambda: chan_active(l2, '108x1x0', True)) l1.rpc.close(l2.info['id']) bitcoind.generate_block(1, True) @@ -1235,8 +1241,8 @@ def no_more_blocks(req): # Unblinding l2 brings it back in sync, restarts channeld and sends its announce sig l2.daemon.rpcproxy.mock_rpc('getblockhash', None) - wait_for(lambda: [c['active'] for c in l2.rpc.listchannels('103x1x0')['channels']] == [False, False]) - wait_for(lambda: [c['active'] for c in l2.rpc.listchannels('104x1x0')['channels']] == [True, True]) + wait_for(lambda: chan_active(l2, '103x1x0', False)) + wait_for(lambda: chan_active(l2, '104x1x0', True)) wait_for(lambda: only_one(l2.rpc.listpeers()['peers'][0]['channels'])['status'] == [ 'CHANNELD_NORMAL:Reconnected, and reestablished.',