diff --git a/.github/workflows/prototest.yaml b/.github/workflows/prototest.yaml deleted file mode 100644 index f333ef880551..000000000000 --- a/.github/workflows/prototest.yaml +++ /dev/null @@ -1,37 +0,0 @@ ---- -name: LN Proto Test -on: - push: - branches: - - "master" - pull_request: -jobs: - proto-test: - name: Protocol Test Config - runs-on: ubuntu-22.04 - timeout-minutes: 120 - strategy: - fail-fast: true - matrix: - include: - - {compiler: clang, db: sqlite3} - - {compiler: gcc, db: postgres} - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Build and run - run: | - docker build -f contrib/docker/Dockerfile.ubuntu -t cln-ci-ubuntu . - docker run -e ARCH=${{ matrix.arch }} \ - -e COMPILER=${{ matrix.compiler }} \ - -e DB=${{ matrix.db }} \ - -e NETWORK=${{ matrix.network }} \ - -e TARGET_HOST=${{ matrix.TARGET_HOST }} \ - -e VALGRIND=${{ matrix.valgrind }} \ - -e PYTEST_PAR=2 \ - -e PYTEST_OPTS="--timeout=300" \ - -e TEST_CMD="make check-protos" \ - -e TEST_GROUP=1 \ - -e TEST_GROUP_COUNT=1 \ - -e TIMEOUT=120 \ - cln-ci-ubuntu diff --git a/.gitmodules b/.gitmodules index 6dae35a54444..4788bedb3fd4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -14,9 +14,6 @@ [submodule "external/gheap"] path = external/gheap url = https://github.com/valyala/gheap -[submodule "external/lnprototest"] - path = external/lnprototest - url = https://github.com/rustyrussell/lnprototest.git [submodule "external/lowdown"] path = external/lowdown url = https://github.com/kristapsdz/lowdown.git diff --git a/.msggen.json b/.msggen.json index e91e8fbc1828..6afde91ade84 100644 --- a/.msggen.json +++ b/.msggen.json @@ -939,6 +939,7 @@ "ListClosedChannels.closedchannels[].funding_txid": 12, "ListClosedChannels.closedchannels[].last_commitment_fee_msat": 23, "ListClosedChannels.closedchannels[].last_commitment_txid": 22, + "ListClosedChannels.closedchannels[].last_stable_connection": 25, "ListClosedChannels.closedchannels[].leased": 14, "ListClosedChannels.closedchannels[].max_to_us_msat": 21, "ListClosedChannels.closedchannels[].min_to_us_msat": 20, @@ -1147,6 +1148,7 @@ "ListPeerChannels.channels[].inflight[]": 16, "ListPeerChannels.channels[].initial_feerate": 12, "ListPeerChannels.channels[].last_feerate": 13, + "ListPeerChannels.channels[].last_stable_connection": 56, "ListPeerChannels.channels[].max_accepted_htlcs": 40, "ListPeerChannels.channels[].max_to_us_msat": 25, "ListPeerChannels.channels[].max_total_htlc_in_msat": 30, @@ -3676,6 +3678,10 @@ "added": "pre-v0.10.1", "deprecated": false }, + "ListClosedChannels.closedchannels[].last_stable_connection": { + "added": "v24.02", + "deprecated": false + }, "ListClosedChannels.closedchannels[].leased": { "added": "pre-v0.10.1", "deprecated": false @@ -4408,6 +4414,10 @@ "added": "v23.02", "deprecated": false }, + "ListPeerChannels.channels[].last_stable_connection": { + "added": "v24.02", + "deprecated": false + }, "ListPeerChannels.channels[].max_accepted_htlcs": { "added": "v23.02", "deprecated": false diff --git a/Makefile b/Makefile index 4ebd478924e5..e6da7a1b8d10 100644 --- a/Makefile +++ b/Makefile @@ -72,7 +72,7 @@ endif # (method=thread to support xdist) PYTEST_OPTS := -v -p no:logging $(PYTEST_OPTS) -MY_CHECK_PYTHONPATH=$${PYTHONPATH}$${PYTHONPATH:+:}$(shell pwd)/contrib/pyln-client:$(shell pwd)/contrib/pyln-testing:$(shell pwd)/contrib/pyln-proto/:$(shell pwd)/external/lnprototest:$(shell pwd)/contrib/pyln-spec/bolt1:$(shell pwd)/contrib/pyln-spec/bolt2:$(shell pwd)/contrib/pyln-spec/bolt4:$(shell pwd)/contrib/pyln-spec/bolt7 +MY_CHECK_PYTHONPATH=$${PYTHONPATH}$${PYTHONPATH:+:}$(shell pwd)/contrib/pyln-client:$(shell pwd)/contrib/pyln-testing:$(shell pwd)/contrib/pyln-proto/:$(shell pwd)/contrib/pyln-spec/bolt1:$(shell pwd)/contrib/pyln-spec/bolt2:$(shell pwd)/contrib/pyln-spec/bolt4:$(shell pwd)/contrib/pyln-spec/bolt7 # Collect generated python files to be excluded from lint checks PYTHON_GENERATED= \ contrib/pyln-grpc-proto/pyln/grpc/primitives_pb2.py \ @@ -453,14 +453,7 @@ endif check-units: -check: check-units installcheck check-protos pytest - -check-protos: $(ALL_PROGRAMS) -ifeq ($(PYTEST),) - @echo "py.test is required to run the protocol tests, please install using 'pip3 install -r requirements.txt', and rerun 'configure'."; false -else - @(cd external/lnprototest && PYTHONPATH=$(MY_CHECK_PYTHONPATH) LIGHTNING_SRC=../.. $(PYTEST) --runner lnprototest.clightning.Runner $(PYTEST_OPTS)) -endif +check: check-units installcheck pytest pytest: $(ALL_PROGRAMS) $(DEFAULT_TARGETS) $(ALL_TEST_PROGRAMS) $(ALL_TEST_GEN) ifeq ($(PYTEST),) diff --git a/channeld/Makefile b/channeld/Makefile index 8bd27e42566f..940cd1128e09 100644 --- a/channeld/Makefile +++ b/channeld/Makefile @@ -83,7 +83,6 @@ CHANNELD_COMMON_OBJS := \ common/psbt_keypath.o \ common/psbt_open.o \ common/psbt_internal.o \ - common/private_channel_announcement.o \ common/pseudorand.o \ common/read_peer_msg.o \ common/setup.o \ diff --git a/channeld/channeld.c b/channeld/channeld.c index 2cb2f198b6b3..95c7c14c0c05 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -128,16 +127,11 @@ struct peer { /* Current blockheight */ u32 our_blockheight; - /* Announcement related information */ - struct node_id node_ids[NUM_SIDES]; + /* FIXME: Remove this. */ struct short_channel_id short_channel_ids[NUM_SIDES]; - secp256k1_ecdsa_signature announcement_node_sigs[NUM_SIDES]; - secp256k1_ecdsa_signature announcement_bitcoin_sigs[NUM_SIDES]; - bool have_sigs[NUM_SIDES]; - bool send_duplicate_announce_sigs; - /* Which direction of the channel do we control? */ - u16 channel_direction; + /* Local scid alias */ + struct short_channel_id local_alias; /* The scriptpubkey to use for shutting down. */ u32 *final_index; @@ -172,18 +166,12 @@ struct peer { /* If set, don't fire commit counter when this hits 0 */ u32 *dev_disable_commit; - /* If set, send channel_announcement after 1 second, not 30 */ - bool dev_fast_gossip; - /* Information used for reestablishment. */ bool last_was_revoke; struct changed_htlc *last_sent_commit; u64 revocations_received; u8 channel_flags; - bool announce_depth_reached; - bool channel_local_active; - /* Make sure timestamps move forward. */ u32 last_update_timestamp; @@ -202,27 +190,16 @@ struct peer { /* We allow a 'tx-sigs' message between reconnect + channel_ready */ bool tx_sigs_allowed; - /* Have we announced the real scid with a - * local_channel_announcement? This can be different from the - * `channel_local_active` flag in case we are using zeroconf, - * in which case we'll have announced the channels with the - * two aliases (LOCAL and REMOTE) but not with the real scid - * just yet. If we get a funding depth change, with a scid, - * and the two flags not equal we know we have to announce the - * channel with the real scid. */ - bool gossip_scid_announced; - /* --experimental-upgrade-protocol */ bool experimental_upgrade; }; -static u8 *create_channel_announcement(const tal_t *ctx, struct peer *peer); static void start_commit_timer(struct peer *peer); static void billboard_update(const struct peer *peer) { const char *update = billboard_message(tmpctx, peer->channel_ready, - peer->have_sigs, + NULL, peer->shutdown_sent, peer->depth_togo, num_channel_htlcs(peer->channel)); @@ -404,271 +381,6 @@ static void set_channel_type(struct channel *channel, const u8 *type) take(towire_channeld_upgraded(NULL, channel->type))); } -/* Tell gossipd to create channel_update (then it goes into - * gossip_store, then streams out to peers, or sends it directly if - * it's a private channel) */ -static void send_channel_update(struct peer *peer, bool enable) -{ - u8 *msg; - - /* Only send an update if we told gossipd */ - if (!peer->channel_local_active) - return; - - assert(peer->short_channel_ids[LOCAL].u64); - - msg = towire_channeld_local_channel_update(NULL, enable); - wire_sync_write(MASTER_FD, take(msg)); -} - -/* Tell gossipd and the other side what parameters we expect should - * they route through us */ -static void send_channel_initial_update(struct peer *peer) -{ - /* If `stfu` is already active then the channel is being mutated quickly - * after creation. These mutations (ie. splice) must announce the - * channel when they finish anyway, so it is safe to skip it here */ - if (!is_stfu_active(peer) && !peer->want_stfu) - send_channel_update(peer, true); -} - -/** - * Add a channel locally and send a channel update to the peer - * - * Send a local_add_channel message to gossipd in order to make the channel - * usable locally, and also tell our peer about our parameters via a - * channel_update message. The peer may accept the update and use the contained - * information to route incoming payments through the channel. The - * channel_update is not preceeded by a channel_announcement and won't make much - * sense to other nodes, so we don't tell gossipd about it. - */ -static void make_channel_local_active(struct peer *peer) -{ - u8 *msg; - const u8 *annfeatures = get_agreed_channelfeatures(tmpctx, - peer->our_features, - peer->their_features); - - /* Tell lightningd to tell gossipd about local channel. */ - msg = towire_channeld_local_private_channel(NULL, - peer->channel->funding_sats, - annfeatures); - wire_sync_write(MASTER_FD, take(msg)); - - /* Under CI, because blocks come so fast, we often find that the - * peer sends its first channel_update before the above message has - * reached it. */ - notleak(new_reltimer(&peer->timers, peer, - time_from_sec(5), - send_channel_initial_update, peer)); -} - -static void send_announcement_signatures(struct peer *peer) -{ - /* First 2 + 256 byte are the signatures and msg type, skip them */ - size_t offset = 258; - struct sha256_double hash; - const u8 *msg, *ca, *req; - struct pubkey mykey; - - status_debug("Exchanging announcement signatures."); - ca = create_channel_announcement(tmpctx, peer); - req = towire_hsmd_cannouncement_sig_req(tmpctx, ca); - - msg = hsm_req(tmpctx, req); - if (!fromwire_hsmd_cannouncement_sig_reply(msg, - &peer->announcement_node_sigs[LOCAL], - &peer->announcement_bitcoin_sigs[LOCAL])) - status_failed(STATUS_FAIL_HSM_IO, - "Reading cannouncement_sig_resp: %s", - strerror(errno)); - - /* Double-check that HSM gave valid signatures. */ - sha256_double(&hash, ca + offset, tal_count(ca) - offset); - if (!pubkey_from_node_id(&mykey, &peer->node_ids[LOCAL])) - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Could not convert my id '%s' to pubkey", - type_to_string(tmpctx, struct node_id, - &peer->node_ids[LOCAL])); - if (!check_signed_hash(&hash, &peer->announcement_node_sigs[LOCAL], - &mykey)) { - /* It's ok to fail here, the channel announcement is - * unique, unlike the channel update which may have - * been replaced in the meantime. */ - status_failed(STATUS_FAIL_HSM_IO, - "HSM returned an invalid node signature"); - } - - if (!check_signed_hash(&hash, &peer->announcement_bitcoin_sigs[LOCAL], - &peer->channel->funding_pubkey[LOCAL])) { - /* It's ok to fail here, the channel announcement is - * unique, unlike the channel update which may have - * been replaced in the meantime. */ - status_failed(STATUS_FAIL_HSM_IO, - "HSM returned an invalid bitcoin signature"); - } - - msg = towire_announcement_signatures( - NULL, &peer->channel_id, &peer->short_channel_ids[LOCAL], - &peer->announcement_node_sigs[LOCAL], - &peer->announcement_bitcoin_sigs[LOCAL]); - peer_write(peer->pps, take(msg)); -} - -/* Tentatively create a channel_announcement, possibly with invalid - * signatures. The signatures need to be collected first, by asking - * the HSM and by exchanging announcement_signature messages. */ -static u8 *create_channel_announcement(const tal_t *ctx, struct peer *peer) -{ - int first, second; - u8 *cannounce, *features - = get_agreed_channelfeatures(tmpctx, peer->our_features, - peer->their_features); - - if (peer->channel_direction == 0) { - first = LOCAL; - second = REMOTE; - } else { - first = REMOTE; - second = LOCAL; - } - - cannounce = towire_channel_announcement( - ctx, &peer->announcement_node_sigs[first], - &peer->announcement_node_sigs[second], - &peer->announcement_bitcoin_sigs[first], - &peer->announcement_bitcoin_sigs[second], - features, - &chainparams->genesis_blockhash, - &peer->short_channel_ids[LOCAL], - &peer->node_ids[first], - &peer->node_ids[second], - &peer->channel->funding_pubkey[first], - &peer->channel->funding_pubkey[second]); - return cannounce; -} - -/* Once we have both, we'd better make sure we agree what they are! */ -static void check_short_ids_match(struct peer *peer) -{ - assert(peer->have_sigs[LOCAL]); - assert(peer->have_sigs[REMOTE]); - - if (!short_channel_id_eq(&peer->short_channel_ids[LOCAL], - &peer->short_channel_ids[REMOTE])) - peer_failed_warn(peer->pps, &peer->channel_id, - "We disagree on short_channel_ids:" - " I have %s, you say %s", - type_to_string(peer, struct short_channel_id, - &peer->short_channel_ids[LOCAL]), - type_to_string(peer, struct short_channel_id, - &peer->short_channel_ids[REMOTE])); -} - -static void announce_channel(struct peer *peer) -{ - u8 *cannounce; - - /* If we splice quickly enough, the initial channel announcement may - * still be pending. This old announcement is made stale by splicing, - * so we ommit it. */ - if (!peer->have_sigs[LOCAL] || !peer->have_sigs[REMOTE]) - return; - - cannounce = create_channel_announcement(tmpctx, peer); - - wire_sync_write(MASTER_FD, - take(towire_channeld_local_channel_announcement(NULL, - cannounce))); - send_channel_update(peer, true); -} - -static void announce_channel_if_not_stfu(struct peer *peer) -{ - if (!is_stfu_active(peer) && !peer->want_stfu) - announce_channel(peer); -} - -/* Returns true if an announcement was sent */ -static bool channel_announcement_negotiate(struct peer *peer) -{ - bool sent_announcement = false; - - /* Don't do any announcement work if we're shutting down */ - if (peer->shutdown_sent[LOCAL]) - return false; - - /* Can't do anything until funding is locked. */ - if (!peer->channel_ready[LOCAL] || !peer->channel_ready[REMOTE]) - return false; - - /* Don't announce channel if we're in stfu mode */ - if (peer->want_stfu || is_stfu_active(peer)) - return false; - - if (!peer->channel_local_active) { - peer->channel_local_active = true; - make_channel_local_active(peer); - } else if(!peer->gossip_scid_announced) { - /* So we know a short_channel_id, i.e., a point on - * chain, but haven't added it to our local view of - * the gossip yet. We need to add it now (and once - * only), so our `channel_update` we'll send a couple - * of lines down has something to attach to. */ - peer->gossip_scid_announced = true; - make_channel_local_active(peer); - } - - /* BOLT #7: - * - * A node: - * - if the `open_channel` message has the `announce_channel` bit set AND a `shutdown` message has not been sent: - * - MUST send the `announcement_signatures` message. - * - MUST NOT send `announcement_signatures` messages until `channel_ready` - * has been sent and received AND the funding transaction has at least six confirmations. - * - otherwise: - * - MUST NOT send the `announcement_signatures` message. - */ - if (!(peer->channel_flags & CHANNEL_FLAGS_ANNOUNCE_CHANNEL)) - return false; - - /* BOLT #7: - * - * - MUST NOT send `announcement_signatures` messages until `channel_ready` - * has been sent and received AND the funding transaction has at least six confirmations. - */ - if (peer->announce_depth_reached && !peer->have_sigs[LOCAL]) { - /* When we reenable the channel, we will also send the announcement to remote peer, and - * receive the remote announcement reply. But we will rebuild the channel with announcement - * from the DB directly, other than waiting for the remote announcement reply. - */ - send_announcement_signatures(peer); - peer->have_sigs[LOCAL] = true; - billboard_update(peer); - sent_announcement = true; - } - - /* If we've completed the signature exchange, we can send a real - * announcement, otherwise we send a temporary one */ - if (peer->have_sigs[LOCAL] && peer->have_sigs[REMOTE]) { - check_short_ids_match(peer); - - /* After making sure short_channel_ids match, we can send remote - * announcement to MASTER. */ - wire_sync_write(MASTER_FD, - take(towire_channeld_got_announcement(NULL, - &peer->announcement_node_sigs[REMOTE], - &peer->announcement_bitcoin_sigs[REMOTE]))); - - /* Give other nodes time to notice new block. */ - notleak(new_reltimer(&peer->timers, peer, - time_from_sec(GOSSIP_ANNOUNCE_DELAY(peer->dev_fast_gossip)), - announce_channel_if_not_stfu, peer)); - } - - return sent_announcement; -} - static void lock_signer_outpoint(const struct bitcoin_outpoint *outpoint) { const u8 *msg; @@ -736,10 +448,6 @@ static void check_mutual_splice_locked(struct peer *peer) peer->splice_state->locked_ready[LOCAL] = false; peer->splice_state->locked_ready[REMOTE] = false; - peer->have_sigs[LOCAL] = false; - peer->have_sigs[REMOTE] = false; - peer->send_duplicate_announce_sigs = true; - peer->splice_state->last_short_channel_id = peer->short_channel_ids[LOCAL]; peer->short_channel_ids[LOCAL] = peer->splice_state->short_channel_id; peer->short_channel_ids[REMOTE] = peer->splice_state->short_channel_id; @@ -789,11 +497,6 @@ static void check_mutual_splice_locked(struct peer *peer) &inflight->outpoint.txid); wire_sync_write(MASTER_FD, take(msg)); - /* We must regossip the scid since it has changed */ - peer->gossip_scid_announced = false; - - if (channel_announcement_negotiate(peer)) - send_channel_update(peer, true); billboard_update(peer); peer->splice_state->inflights = tal_free(peer->splice_state->inflights); @@ -876,115 +579,29 @@ static void handle_peer_channel_ready(struct peer *peer, const u8 *msg) take(towire_channeld_got_channel_ready( NULL, &peer->remote_per_commit, tlvs->short_channel_id))); - channel_announcement_negotiate(peer); billboard_update(peer); - peer->send_duplicate_announce_sigs = true; -} - -/* Checks that key is valid, and signed this hash - * - * FIXME: move this inside common/utils.h */ -static bool check_signed_hash_nodeid(const struct sha256_double *hash, - const secp256k1_ecdsa_signature *signature, - const struct node_id *id) -{ - struct pubkey key; - - return pubkey_from_node_id(&key, id) - && check_signed_hash(hash, signature, &key); } static void handle_peer_announcement_signatures(struct peer *peer, const u8 *msg) { - const u8 *cannounce; struct channel_id chanid; - struct sha256_double hash; struct short_channel_id remote_scid; + secp256k1_ecdsa_signature remote_node_sig, remote_bitcoin_sig; if (!fromwire_announcement_signatures(msg, &chanid, &remote_scid, - &peer->announcement_node_sigs[REMOTE], - &peer->announcement_bitcoin_sigs[REMOTE])) + &remote_node_sig, + &remote_bitcoin_sig)) peer_failed_warn(peer->pps, &peer->channel_id, "Bad announcement_signatures %s", tal_hex(msg, msg)); - /* BOLT-0d8b701614b09c6ee4172b04da2203e73deec7e2 #2: - * Once a node has received and sent `splice_locked`: - * - Until sending OR receiving of `revoke_and_ack` - * - MUST ignore `announcement_signatures` messages where - * `short_channel_id` matches the pre-splice short channel id. */ - if (peer->splice_state->await_commitment_succcess - && !short_channel_id_eq(&remote_scid, - &peer->short_channel_ids[LOCAL])) { - status_info("Ignoring stale announcement_signatures: expected" - " %s, got %s", - type_to_string(tmpctx, struct short_channel_id, - &peer->short_channel_ids[LOCAL]), - type_to_string(tmpctx, struct short_channel_id, - &remote_scid)); - return; - } - - peer->short_channel_ids[REMOTE] = remote_scid; - - /* Make sure we agree on the channel ids */ - if (!channel_id_eq(&chanid, &peer->channel_id)) { - peer_failed_err(peer->pps, &chanid, - "Wrong channel_id: expected %s, got %s", - type_to_string(tmpctx, struct channel_id, - &peer->channel_id), - type_to_string(tmpctx, struct channel_id, &chanid)); - } - - /* BOLT 7: - * - if the node_signature OR the bitcoin_signature is NOT correct: - * - MAY send a warning and close the connection, or send an error and fail the channel. - * - * In our case, we send an error and stop the open channel procedure. This approach is - * considered overly strict since the peer can recover from it. However, this step is - * optional. If the peer sends it, we assume that the signature must be correct.*/ - cannounce = create_channel_announcement(tmpctx, peer); - - /* 2 byte msg type + 256 byte signatures */ - int offset = 258; - sha256_double(&hash, cannounce + offset, - tal_count(cannounce) - offset); - - if (!check_signed_hash_nodeid(&hash, &peer->announcement_node_sigs[REMOTE], &peer->node_ids[REMOTE])) { - peer_failed_warn(peer->pps, &chanid, - "Bad node_signature %s hash %s" - " on announcement_signatures %s", - type_to_string(tmpctx, - secp256k1_ecdsa_signature, - &peer->announcement_node_sigs[REMOTE]), - type_to_string(tmpctx, - struct sha256_double, - &hash), - tal_hex(tmpctx, cannounce)); - } - if (!check_signed_hash(&hash, &peer->announcement_bitcoin_sigs[REMOTE], &peer->channel->funding_pubkey[REMOTE])) { - peer_failed_warn(peer->pps, &chanid, - "Bad bitcoin_signature %s hash %s" - " on announcement_signatures %s", - type_to_string(tmpctx, - secp256k1_ecdsa_signature, - &peer->announcement_bitcoin_sigs[REMOTE]), - type_to_string(tmpctx, - struct sha256_double, - &hash), - tal_hex(tmpctx, cannounce)); - } - peer->have_sigs[REMOTE] = true; - billboard_update(peer); - - if (!channel_announcement_negotiate(peer) - && peer->send_duplicate_announce_sigs - && peer->have_sigs[LOCAL]) { - peer->send_duplicate_announce_sigs = false; - send_announcement_signatures(peer); - } + wire_sync_write(MASTER_FD, + take(towire_channeld_got_announcement(NULL, + &remote_scid, + &remote_node_sig, + &remote_bitcoin_sig))); } static void handle_peer_add_htlc(struct peer *peer, const u8 *msg) @@ -1226,10 +843,6 @@ static void maybe_send_shutdown(struct peer *peer) /* DTODO: Ensure 'shutdown' rules around splice are followed once those * rules get settled on spec */ - /* Send a disable channel_update so others don't try to route - * over us */ - send_channel_update(peer, false); - if (peer->shutdown_wrong_funding) { tlvs = tlv_shutdown_tlvs_new(tmpctx); tlvs->wrong_funding @@ -2609,9 +2222,6 @@ static void handle_peer_shutdown(struct peer *peer, const u8 *shutdown) /* DTODO: Ensure `shutdown` follows new splice related rules once * completed in the spec */ - /* Disable the channel. */ - send_channel_update(peer, false); - if (!fromwire_shutdown(tmpctx, shutdown, &channel_id, &scriptpubkey, &tlvs)) peer_failed_warn(peer->pps, &peer->channel_id, @@ -3760,8 +3370,6 @@ static void resume_splice_negotiation(struct peer *peer, msg = towire_channeld_splice_confirmed_signed(tmpctx, final_tx, chan_output_index); wire_sync_write(MASTER_FD, take(msg)); - - send_channel_update(peer, true); } } @@ -5272,6 +4880,7 @@ static void peer_reconnect(struct peer *peer, && next_commitment_number == 1) { struct tlv_channel_ready_tlvs *tlvs = tlv_channel_ready_tlvs_new(tmpctx); + tlvs->short_channel_id = &peer->local_alias; status_debug("Retransmitting channel_ready for channel %s", type_to_string(tmpctx, struct channel_id, &peer->channel_id)); /* Contains per commit point #1, for first post-opening commit */ @@ -5504,6 +5113,10 @@ static void peer_reconnect(struct peer *peer, /* Now stop, we've been polite long enough. */ if (reestablish_only) { + /* We've reestablished! */ + wire_sync_write(MASTER_FD, + take(towire_channeld_reestablished(NULL))); + /* If we were successfully closing, we still go to closingd. */ if (shutdown_complete(peer)) { send_shutdown_complete(peer); @@ -5517,6 +5130,9 @@ static void peer_reconnect(struct peer *peer, tal_free(send_tlvs); + /* We've reestablished! */ + wire_sync_write(MASTER_FD, take(towire_channeld_reestablished(NULL))); + /* Corner case: we didn't send shutdown before because update_add_htlc * pending, but now they're cleared by restart, and we're actually * complete. In that case, their `shutdown` will trigger us. */ @@ -5554,7 +5170,7 @@ static void peer_reconnect(struct peer *peer, static void handle_funding_depth(struct peer *peer, const u8 *msg) { u32 depth; - struct short_channel_id *scid, *alias_local; + struct short_channel_id *scid; struct tlv_channel_ready_tlvs *tlvs; struct pubkey point; bool splicing; @@ -5563,7 +5179,6 @@ static void handle_funding_depth(struct peer *peer, const u8 *msg) if (!fromwire_channeld_funding_depth(tmpctx, msg, &scid, - &alias_local, &depth, &splicing, &txid)) @@ -5594,15 +5209,15 @@ static void handle_funding_depth(struct peer *peer, const u8 *msg) status_debug("handle_funding_depth: Setting short_channel_ids[LOCAL] to %s", type_to_string(tmpctx, struct short_channel_id, - (scid ? scid : alias_local))); + (scid ? scid : &peer->local_alias))); /* If we know an actual short_channel_id prefer to use * that, otherwise fill in the alias. From channeld's * point of view switching from zeroconf to an actual * funding scid is just a reorg. */ if (scid) peer->short_channel_ids[LOCAL] = *scid; - else if (alias_local) - peer->short_channel_ids[LOCAL] = *alias_local; + else + peer->short_channel_ids[LOCAL] = peer->local_alias; } if (!peer->channel_ready[LOCAL]) { @@ -5612,7 +5227,7 @@ static void handle_funding_depth(struct peer *peer, const u8 *msg) type_to_string(tmpctx, struct pubkey, &peer->next_local_per_commit)); tlvs = tlv_channel_ready_tlvs_new(tmpctx); - tlvs->short_channel_id = alias_local; + tlvs->short_channel_id = &peer->local_alias; /* Need to retrieve the first point again, even if we * moved on, as channel_ready explicitly includes the @@ -5637,12 +5252,6 @@ static void handle_funding_depth(struct peer *peer, const u8 *msg) peer->splice_state->locked_ready[LOCAL] = true; check_mutual_splice_locked(peer); } - - peer->announce_depth_reached = (depth >= ANNOUNCE_MIN_DEPTH); - - /* Send temporary or final announcements */ - if (!splicing) - channel_announcement_negotiate(peer); } billboard_update(peer); @@ -6066,14 +5675,12 @@ static void req_in(struct peer *peer, const u8 *msg) case WIRE_CHANNELD_SEND_ERROR_REPLY: case WIRE_CHANNELD_DEV_QUIESCE_REPLY: case WIRE_CHANNELD_UPGRADED: - case WIRE_CHANNELD_LOCAL_CHANNEL_UPDATE: - case WIRE_CHANNELD_LOCAL_CHANNEL_ANNOUNCEMENT: - case WIRE_CHANNELD_LOCAL_PRIVATE_CHANNEL: case WIRE_CHANNELD_ADD_INFLIGHT: case WIRE_CHANNELD_UPDATE_INFLIGHT: case WIRE_CHANNELD_GOT_INFLIGHT: case WIRE_CHANNELD_SPLICE_STATE_ERROR: case WIRE_CHANNELD_LOCAL_ANCHOR_INFO: + case WIRE_CHANNELD_REESTABLISHED: break; } master_badmsg(-1, msg); @@ -6099,8 +5706,6 @@ static void init_channel(struct peer *peer) 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; struct penalty_base *pbases; bool reestablish_only; struct channel_type *channel_type; @@ -6133,8 +5738,6 @@ static void init_channel(struct peer *peer) &local_msat, &points[LOCAL], &funding_pubkey[LOCAL], - &peer->node_ids[LOCAL], - &peer->node_ids[REMOTE], &peer->commit_msec, &peer->last_was_revoke, &peer->last_sent_commit, @@ -6154,19 +5757,16 @@ static void init_channel(struct peer *peer) &peer->final_scriptpubkey, &peer->channel_flags, &fwd_msg, - &peer->announce_depth_reached, &last_remote_per_commit_secret, &peer->their_features, &peer->remote_upfront_shutdown_script, - &remote_ann_node_sig, - &remote_ann_bitcoin_sig, &channel_type, - &peer->dev_fast_gossip, &peer->dev_disable_commit, &pbases, &reestablish_only, &peer->experimental_upgrade, - &peer->splice_state->inflights)) { + &peer->splice_state->inflights, + &peer->local_alias)) { master_badmsg(WIRE_CHANNELD_INIT, msg); } @@ -6211,20 +5811,6 @@ static void init_channel(struct peer *peer) type_to_string(tmpctx, struct height_states, blockheight_states), peer->our_blockheight); - if (remote_ann_node_sig && remote_ann_bitcoin_sig) { - peer->announcement_node_sigs[REMOTE] = *remote_ann_node_sig; - peer->announcement_bitcoin_sigs[REMOTE] = *remote_ann_bitcoin_sig; - peer->have_sigs[REMOTE] = true; - - /* Before we store announcement into DB, we have made sure - * remote short_channel_id matched the local. Now we initial - * it directly! - */ - peer->short_channel_ids[REMOTE] = peer->short_channel_ids[LOCAL]; - tal_free(remote_ann_node_sig); - tal_free(remote_ann_bitcoin_sig); - } - /* First commit is used for opening: if we've sent 0, we're on * index 1. */ assert(peer->next_index[LOCAL] > 0); @@ -6260,9 +5846,6 @@ static void init_channel(struct peer *peer) update_view_from_inflights(peer); - peer->channel_direction = node_id_idx(&peer->node_ids[LOCAL], - &peer->node_ids[REMOTE]); - /* Default desired feerate is the feerate we set for them last. */ if (peer->channel->opener == LOCAL) peer->desired_feerate = channel_feerate(peer->channel, REMOTE); @@ -6281,9 +5864,6 @@ static void init_channel(struct peer *peer) if (fwd_msg) peer_write(peer->pps, take(fwd_msg)); - /* Reenable channel */ - channel_announcement_negotiate(peer); - billboard_update(peer); } @@ -6291,7 +5871,7 @@ int main(int argc, char *argv[]) { setup_locale(); - int i, nfds; + int nfds; fd_set fds_in, fds_out; struct peer *peer; bool developer; @@ -6304,16 +5884,11 @@ int main(int argc, char *argv[]) peer->developer = developer; timers_init(&peer->timers, time_mono()); peer->commit_timer = NULL; - peer->have_sigs[LOCAL] = peer->have_sigs[REMOTE] = false; - peer->announce_depth_reached = false; - peer->channel_local_active = false; - peer->gossip_scid_announced = false; peer->from_master = msg_queue_new(peer, true); peer->shutdown_sent[LOCAL] = false; peer->shutdown_wrong_funding = NULL; peer->last_update_timestamp = 0; peer->last_empty_commitment = 0; - peer->send_duplicate_announce_sigs = false; peer->want_stfu = false; peer->stfu_sent[LOCAL] = peer->stfu_sent[REMOTE] = false; peer->stfu_wait_single_msg = false; @@ -6322,15 +5897,6 @@ int main(int argc, char *argv[]) peer->splice_state = splice_state_new(peer); peer->splicing = NULL; - /* We send these to HSM to get real signatures; don't have valgrind - * complain. */ - for (i = 0; i < NUM_SIDES; i++) { - memset(&peer->announcement_node_sigs[i], 0, - sizeof(peer->announcement_node_sigs[i])); - memset(&peer->announcement_bitcoin_sigs[i], 0, - sizeof(peer->announcement_bitcoin_sigs[i])); - } - /* Prepare the ecdh() function for use */ ecdh_hsmd_setup(HSM_FD, status_failed); diff --git a/channeld/channeld_wire.csv b/channeld/channeld_wire.csv index fcc76b5ff8a0..b62d291b17f0 100644 --- a/channeld/channeld_wire.csv +++ b/channeld/channeld_wire.csv @@ -39,8 +39,6 @@ msgdata,channeld_init,opener,enum side, msgdata,channeld_init,local_msatoshi,amount_msat, msgdata,channeld_init,our_basepoints,basepoints, msgdata,channeld_init,our_funding_pubkey,pubkey, -msgdata,channeld_init,local_node_id,node_id, -msgdata,channeld_init,remote_node_id,node_id, msgdata,channeld_init,commit_msec,u32, msgdata,channeld_init,last_was_revoke,bool, msgdata,channeld_init,num_last_sent_commit,u16, @@ -64,16 +62,12 @@ msgdata,channeld_init,final_scriptpubkey,u8,final_scriptpubkey_len msgdata,channeld_init,flags,u8, msgdata,channeld_init,init_peer_pkt_len,u16, msgdata,channeld_init,init_peer_pkt,u8,init_peer_pkt_len -msgdata,channeld_init,reached_announce_depth,bool, msgdata,channeld_init,last_remote_secret,secret, msgdata,channeld_init,flen,u16, msgdata,channeld_init,their_features,u8,flen msgdata,channeld_init,upfront_shutdown_script_len,u16, msgdata,channeld_init,upfront_shutdown_script,u8,upfront_shutdown_script_len -msgdata,channeld_init,remote_ann_node_sig,?secp256k1_ecdsa_signature, -msgdata,channeld_init,remote_ann_bitcoin_sig,?secp256k1_ecdsa_signature, msgdata,channeld_init,desired_type,channel_type, -msgdata,channeld_init,dev_fast_gossip,bool, msgdata,channeld_init,dev_disable_commit,?u32, msgdata,channeld_init,num_penalty_bases,u32, msgdata,channeld_init,pbases,penalty_base,num_penalty_bases @@ -81,13 +75,15 @@ msgdata,channeld_init,reestablish_only,bool, msgdata,channeld_init,experimental_upgrade,bool, msgdata,channeld_init,num_inflights,u16, msgdata,channeld_init,inflights,inflight,num_inflights +msgdata,channeld_init,scid_alias,short_channel_id, + +# channeld->lightningd: successfully negotated reestablishment. +msgtype,channeld_reestablished,1101 # master->channeld funding hit new depth(funding locked if >= lock depth) -# alias != NULL if zeroconf and short_channel_id == NULL # short_channel_id != NULL once we have 3+ confirmations msgtype,channeld_funding_depth,1002 msgdata,channeld_funding_depth,short_channel_id,?short_channel_id, -msgdata,channeld_funding_depth,alias_local,?short_channel_id, msgdata,channeld_funding_depth,depth,u32, msgdata,channeld_funding_depth,splicing,bool, msgdata,channeld_funding_depth,txid,bitcoin_txid, @@ -324,6 +320,7 @@ msgdata,channeld_fail_fallen_behind,remote_per_commitment_point,?pubkey, # When we receive announcement_signatures for channel announce msgtype,channeld_got_announcement,1017 +msgdata,channeld_got_announcement,scid,short_channel_id, msgdata,channeld_got_announcement,remote_ann_node_sig,secp256k1_ecdsa_signature, msgdata,channeld_got_announcement,remote_ann_bitcoin_sig,secp256k1_ecdsa_signature, @@ -334,21 +331,6 @@ msgdata,channeld_send_error,reason,wirestring, # Tell master channeld has sent the error message. msgtype,channeld_send_error_reply,1108 -# Channeld: tell gossipd to make channel_update to enable/disable. -msgtype,channeld_local_channel_update,1013 -msgdata,channeld_local_channel_update,enable,bool, - -# Channeld: tell gossipd about our channel_announcement -msgtype,channeld_local_channel_announcement,1014 -msgdata,channeld_local_channel_announcement,len,u16, -msgdata,channeld_local_channel_announcement,cannounce,u8,len - -# Channeld: tell gossipd about this (as-yet) unannounced channel -msgtype,channeld_local_private_channel,1015 -msgdata,channeld_local_private_channel,capacity,amount_sat, -msgdata,channeld_local_private_channel,len,u16, -msgdata,channeld_local_private_channel,features,u8,len - # Ask channeld to quiesce. msgtype,channeld_dev_quiesce,1009 msgtype,channeld_dev_quiesce_reply,1109 diff --git a/cln-grpc/proto/node.proto b/cln-grpc/proto/node.proto index e8228ebff95d..ff2fc7dce11c 100644 --- a/cln-grpc/proto/node.proto +++ b/cln-grpc/proto/node.proto @@ -1235,6 +1235,7 @@ message ListpeerchannelsChannels { optional Amount out_offered_msat = 49; optional uint64 out_payments_fulfilled = 50; optional Amount out_fulfilled_msat = 51; + optional uint64 last_stable_connection = 56; repeated ListpeerchannelsChannelsHtlcs htlcs = 52; optional string close_to_addr = 53; } @@ -1345,6 +1346,7 @@ message ListclosedchannelsClosedchannels { optional bytes last_commitment_txid = 22; optional Amount last_commitment_fee_msat = 23; ListclosedchannelsClosedchannelsClose_cause close_cause = 24; + optional uint64 last_stable_connection = 25; } message ListclosedchannelsClosedchannelsAlias { diff --git a/cln-grpc/src/convert.rs b/cln-grpc/src/convert.rs index e7c207290f5e..bb6678c25c0e 100644 --- a/cln-grpc/src/convert.rs +++ b/cln-grpc/src/convert.rs @@ -1168,6 +1168,7 @@ impl From for pb::ListpeerchannelsChannels out_offered_msat: c.out_offered_msat.map(|f| f.into()), // Rule #2 for type msat? out_payments_fulfilled: c.out_payments_fulfilled, // Rule #2 for type u64? out_fulfilled_msat: c.out_fulfilled_msat.map(|f| f.into()), // Rule #2 for type msat? + last_stable_connection: c.last_stable_connection, // Rule #2 for type u64? // Field: ListPeerChannels.channels[].htlcs[] htlcs: c.htlcs.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3 close_to_addr: c.close_to_addr, // Rule #2 for type string? @@ -1222,6 +1223,7 @@ impl From for pb::Listclosedchannel last_commitment_txid: c.last_commitment_txid.map(|v| >::as_ref(&v).to_vec()), // Rule #2 for type hash? last_commitment_fee_msat: c.last_commitment_fee_msat.map(|f| f.into()), // Rule #2 for type msat? close_cause: c.close_cause as i32, + last_stable_connection: c.last_stable_connection, // Rule #2 for type u64? } } } diff --git a/cln-rpc/src/model.rs b/cln-rpc/src/model.rs index 23aea73eabdb..287c0b94429b 100644 --- a/cln-rpc/src/model.rs +++ b/cln-rpc/src/model.rs @@ -4676,6 +4676,8 @@ pub mod responses { pub out_payments_fulfilled: Option, #[serde(skip_serializing_if = "Option::is_none")] pub out_fulfilled_msat: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub last_stable_connection: Option, #[serde(skip_serializing_if = "crate::is_none_or_empty")] pub htlcs: Option>, #[serde(skip_serializing_if = "Option::is_none")] @@ -4788,6 +4790,8 @@ pub mod responses { pub last_commitment_fee_msat: Option, // Path `ListClosedChannels.closedchannels[].close_cause` pub close_cause: ListclosedchannelsClosedchannelsClose_cause, + #[serde(skip_serializing_if = "Option::is_none")] + pub last_stable_connection: Option, } #[derive(Clone, Debug, Deserialize, Serialize)] diff --git a/common/Makefile b/common/Makefile index 55da9a41bae5..37529c6fcebc 100644 --- a/common/Makefile +++ b/common/Makefile @@ -77,7 +77,6 @@ COMMON_SRC_NOGEN := \ common/per_peer_state.c \ common/permute_tx.c \ common/ping.c \ - common/private_channel_announcement.c \ common/psbt_internal.c \ common/psbt_keypath.c \ common/psbt_open.c \ diff --git a/common/gossip_store.h b/common/gossip_store.h index ef6394dd7ce6..f1a8525df79a 100644 --- a/common/gossip_store.h +++ b/common/gossip_store.h @@ -15,7 +15,7 @@ struct gossip_rcvd_filter; /* First byte of file is the version. * * Top three bits mean incompatible change. - * As of this writing, major == 0, minor == 11. + * As of this writing, major == 0, minor == 13. */ #define GOSSIP_STORE_MAJOR_VERSION_MASK 0xE0 #define GOSSIP_STORE_MINOR_VERSION_MASK 0x1F diff --git a/common/hsm_version.h b/common/hsm_version.h index 5ca445ce2962..5a2c2deac84a 100644 --- a/common/hsm_version.h +++ b/common/hsm_version.h @@ -21,7 +21,8 @@ * v4 with buried outpoint check: f44fae666895cab0347b3de7c245267c71cc7de834827b83e286e86318c08aec * v4 with forget_channel: d87c6934ea188f92785d38d7cd0b13ed7f76aa7417f3200baf0c7b5aa832fe29 * v5 with hsmd_revoke_commitment_tx: 5742538f87ef5d5bf55b66dc19e52c8683cfeb1b887d3e64ba530ba9a4d8e638 - */ + * v5 with sign_any_cannouncement: 5fdb9068c43a21887dc03f7dce410d2e3eeff6277f0d49b4fc56595a798fd4a4 +*/ #define HSM_MIN_VERSION 3 #define HSM_MAX_VERSION 5 #endif /* LIGHTNING_COMMON_HSM_VERSION_H */ diff --git a/common/node_id.c b/common/node_id.c index 34cda6d54429..902b651b6923 100644 --- a/common/node_id.c +++ b/common/node_id.c @@ -1,5 +1,6 @@ #include "config.h" #include +#include #include #include #include @@ -66,3 +67,13 @@ void towire_node_id(u8 **pptr, const struct node_id *id) #endif towire(pptr, id->k, sizeof(id->k)); } + +bool check_signed_hash_nodeid(const struct sha256_double *hash, + const secp256k1_ecdsa_signature *signature, + const struct node_id *id) +{ + struct pubkey key; + + return pubkey_from_node_id(&key, id) + && check_signed_hash(hash, signature, &key); +} diff --git a/common/node_id.h b/common/node_id.h index 1e2f8d0633c1..110c590ddecf 100644 --- a/common/node_id.h +++ b/common/node_id.h @@ -7,6 +7,8 @@ #include #include +struct sha256_double; + struct node_id { u8 k[PUBKEY_CMPR_LEN]; }; @@ -63,4 +65,18 @@ static inline size_t node_id_hash(const struct node_id *id) { return siphash24(siphash_seed(), id->k, sizeof(id->k)); } + +/** + * check_signed_hash_nodeid - check a raw secp256k1 signature. + * @h: hash which was signed. + * @signature: signature. + * @id: node_id corresponding to private key used to sign. + * + * Returns true if the id, hash and signature are correct. Changing any + * one of these will make it fail. + */ +bool check_signed_hash_nodeid(const struct sha256_double *hash, + const secp256k1_ecdsa_signature *signature, + const struct node_id *id); + #endif /* LIGHTNING_COMMON_NODE_ID_H */ diff --git a/common/private_channel_announcement.c b/common/private_channel_announcement.c deleted file mode 100644 index 9247be3c7b28..000000000000 --- a/common/private_channel_announcement.c +++ /dev/null @@ -1,48 +0,0 @@ -#include "config.h" -#include -#include -#include -#include - -const u8 *private_channel_announcement(const tal_t *ctx, - const struct short_channel_id *scid, - const struct node_id *local_node_id, - const struct node_id *remote_node_id, - const u8 *features) -{ - struct pubkey dummy_pubkey; - const struct node_id *node[2]; - struct secret not_a_secret; - - /* Make an all-zero sig. */ - static const u8 zeros[64]; - size_t zlen = sizeof(zeros); - const u8 *zerop = zeros; - secp256k1_ecdsa_signature zerosig; - fromwire_secp256k1_ecdsa_signature(&zerop, &zlen, &zerosig); - assert(zerop != NULL); - - memset(¬_a_secret, 1, sizeof(not_a_secret)); - if (!pubkey_from_secret(¬_a_secret, &dummy_pubkey)) - abort(); - - /* node ids are in ascending order. */ - if (node_id_cmp(remote_node_id, local_node_id) > 0) { - node[0] = local_node_id; - node[1] = remote_node_id; - } else { - node[0] = remote_node_id; - node[1] = local_node_id; - } - - return towire_channel_announcement(ctx, - &zerosig, &zerosig, - &zerosig, &zerosig, - features, - &chainparams->genesis_blockhash, - scid, - node[0], - node[1], - &dummy_pubkey, - &dummy_pubkey); -} diff --git a/common/private_channel_announcement.h b/common/private_channel_announcement.h deleted file mode 100644 index 45f98d3fc8bb..000000000000 --- a/common/private_channel_announcement.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef LIGHTNING_COMMON_PRIVATE_CHANNEL_ANNOUNCEMENT_H -#define LIGHTNING_COMMON_PRIVATE_CHANNEL_ANNOUNCEMENT_H -#include "config.h" -#include -#include - -struct short_channel_id; -struct node_id; - -/* Helper to create a fake channel announcement for local channels. */ -const u8 *private_channel_announcement(const tal_t *ctx, - const struct short_channel_id *scid, - const struct node_id *local_node_id, - const struct node_id *remote_node_id, - const u8 *features); - -#endif /* LIGHTNING_COMMON_PRIVATE_CHANNEL_ANNOUNCEMENT_H */ diff --git a/connectd/connectd.c b/connectd/connectd.c index 6e1739410fc3..19ea0944aaa0 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -1835,24 +1835,24 @@ static void start_shutdown(struct daemon *daemon, const u8 *msg) take(towire_connectd_start_shutdown_reply(NULL))); } -/* lightningd tells us to send a msg and disconnect. */ -static void peer_final_msg(struct io_conn *conn, +/* lightningd tells us to send a msg. */ +static void peer_send_msg(struct io_conn *conn, struct daemon *daemon, const u8 *msg) { struct peer *peer; struct node_id id; u64 counter; - u8 *finalmsg; + u8 *sendmsg; - if (!fromwire_connectd_peer_final_msg(tmpctx, msg, &id, &counter, - &finalmsg)) - master_badmsg(WIRE_CONNECTD_PEER_FINAL_MSG, msg); + if (!fromwire_connectd_peer_send_msg(tmpctx, msg, &id, &counter, + &sendmsg)) + master_badmsg(WIRE_CONNECTD_PEER_SEND_MSG, msg); /* This can happen if peer hung up on us (or wrong counter * if it reconnected). */ peer = peer_htable_get(daemon->peers, &id); if (peer && peer->counter == counter) - multiplex_final_msg(peer, take(finalmsg)); + inject_peer_msg(peer, take(sendmsg)); } static void dev_connect_memleak(struct daemon *daemon, const u8 *msg) @@ -2078,8 +2078,8 @@ static struct io_plan *recv_req(struct io_conn *conn, peer_discard(daemon, msg); goto out; - case WIRE_CONNECTD_PEER_FINAL_MSG: - peer_final_msg(conn, daemon, msg); + case WIRE_CONNECTD_PEER_SEND_MSG: + peer_send_msg(conn, daemon, msg); goto out; case WIRE_CONNECTD_PING: diff --git a/connectd/connectd_wire.csv b/connectd/connectd_wire.csv index 6b8f9e27d6a0..db895d6c5d08 100644 --- a/connectd/connectd_wire.csv +++ b/connectd/connectd_wire.csv @@ -99,12 +99,12 @@ msgtype,connectd_discard_peer,2015 msgdata,connectd_discard_peer,id,node_id, msgdata,connectd_discard_peer,counter,u64, -# master -> connectd: give message to peer and disconnect. -msgtype,connectd_peer_final_msg,2003 -msgdata,connectd_peer_final_msg,id,node_id, -msgdata,connectd_peer_final_msg,counter,u64, -msgdata,connectd_peer_final_msg,len,u16, -msgdata,connectd_peer_final_msg,msg,u8,len +# master -> connectd: give message to peer. +msgtype,connectd_peer_send_msg,2003 +msgdata,connectd_peer_send_msg,id,node_id, +msgdata,connectd_peer_send_msg,counter,u64, +msgdata,connectd_peer_send_msg,len,u16, +msgdata,connectd_peer_send_msg,msg,u8,len # master -> connectd: do you have a memleak? msgtype,connectd_dev_memleak,2033 diff --git a/connectd/multiplex.c b/connectd/multiplex.c index a3b9e2d08258..3c50a2117ddd 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -167,12 +167,6 @@ void inject_peer_msg(struct peer *peer, const u8 *msg TAKES) msg_enqueue(peer->peer_outq, msg); } -void multiplex_final_msg(struct peer *peer, const u8 *final_msg TAKES) -{ - inject_peer_msg(peer, final_msg); - drain_peer(peer); -} - /* Send warning, close connection to peer */ static void send_warning(struct peer *peer, const char *fmt, ...) { @@ -187,7 +181,8 @@ static void send_warning(struct peer *peer, const char *fmt, ...) msg = towire_warningfmtv(NULL, NULL, fmt, ap); va_end(ap); - multiplex_final_msg(peer, take(msg)); + inject_peer_msg(peer, take(msg)); + drain_peer(peer); } /* Kicks off write_to_peer() to look for more gossip to send from store */ diff --git a/connectd/multiplex.h b/connectd/multiplex.h index 489ab4653825..5988049c7538 100644 --- a/connectd/multiplex.h +++ b/connectd/multiplex.h @@ -14,10 +14,6 @@ struct feature_set; struct io_plan *multiplex_peer_setup(struct io_conn *peer_conn, struct peer *peer); -/* Send this message to peer and disconnect. */ -void multiplex_final_msg(struct peer *peer, - const u8 *final_msg TAKES); - /* Inject a message into the output stream. Unlike a raw msg_enqueue, * this does io logging. */ void inject_peer_msg(struct peer *peer, const u8 *msg TAKES); diff --git a/contrib/pyln-grpc-proto/pyln/grpc/node_pb2.py b/contrib/pyln-grpc-proto/pyln/grpc/node_pb2.py index 9e1c6aad2a5a..bf554a214a46 100644 --- a/contrib/pyln-grpc-proto/pyln/grpc/node_pb2.py +++ b/contrib/pyln-grpc-proto/pyln/grpc/node_pb2.py @@ -14,7 +14,7 @@ from pyln.grpc import primitives_pb2 as primitives__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\nnode.proto\x12\x03\x63ln\x1a\x10primitives.proto\"\x10\n\x0eGetinfoRequest\"\xc1\x04\n\x0fGetinfoResponse\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x12\n\x05\x61lias\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\r\n\x05\x63olor\x18\x03 \x01(\x0c\x12\x11\n\tnum_peers\x18\x04 \x01(\r\x12\x1c\n\x14num_pending_channels\x18\x05 \x01(\r\x12\x1b\n\x13num_active_channels\x18\x06 \x01(\r\x12\x1d\n\x15num_inactive_channels\x18\x07 \x01(\r\x12\x0f\n\x07version\x18\x08 \x01(\t\x12\x15\n\rlightning_dir\x18\t \x01(\t\x12\x33\n\x0cour_features\x18\n \x01(\x0b\x32\x18.cln.GetinfoOur_featuresH\x01\x88\x01\x01\x12\x13\n\x0b\x62lockheight\x18\x0b \x01(\r\x12\x0f\n\x07network\x18\x0c \x01(\t\x12(\n\x13\x66\x65\x65s_collected_msat\x18\r \x01(\x0b\x32\x0b.cln.Amount\x12$\n\x07\x61\x64\x64ress\x18\x0e \x03(\x0b\x32\x13.cln.GetinfoAddress\x12$\n\x07\x62inding\x18\x0f \x03(\x0b\x32\x13.cln.GetinfoBinding\x12\"\n\x15warning_bitcoind_sync\x18\x10 \x01(\tH\x02\x88\x01\x01\x12$\n\x17warning_lightningd_sync\x18\x11 \x01(\tH\x03\x88\x01\x01\x42\x08\n\x06_aliasB\x0f\n\r_our_featuresB\x18\n\x16_warning_bitcoind_syncB\x1a\n\x18_warning_lightningd_sync\"S\n\x13GetinfoOur_features\x12\x0c\n\x04init\x18\x01 \x01(\x0c\x12\x0c\n\x04node\x18\x02 \x01(\x0c\x12\x0f\n\x07\x63hannel\x18\x03 \x01(\x0c\x12\x0f\n\x07invoice\x18\x04 \x01(\x0c\"\xc4\x01\n\x0eGetinfoAddress\x12\x39\n\titem_type\x18\x01 \x01(\x0e\x32&.cln.GetinfoAddress.GetinfoAddressType\x12\x0c\n\x04port\x18\x02 \x01(\r\x12\x14\n\x07\x61\x64\x64ress\x18\x03 \x01(\tH\x00\x88\x01\x01\"G\n\x12GetinfoAddressType\x12\x07\n\x03\x44NS\x10\x00\x12\x08\n\x04IPV4\x10\x01\x12\x08\n\x04IPV6\x10\x02\x12\t\n\x05TORV2\x10\x03\x12\t\n\x05TORV3\x10\x04\x42\n\n\x08_address\"\x8a\x02\n\x0eGetinfoBinding\x12\x39\n\titem_type\x18\x01 \x01(\x0e\x32&.cln.GetinfoBinding.GetinfoBindingType\x12\x14\n\x07\x61\x64\x64ress\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x11\n\x04port\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\x13\n\x06socket\x18\x04 \x01(\tH\x02\x88\x01\x01\"_\n\x12GetinfoBindingType\x12\x10\n\x0cLOCAL_SOCKET\x10\x00\x12\r\n\tWEBSOCKET\x10\x05\x12\x08\n\x04IPV4\x10\x01\x12\x08\n\x04IPV6\x10\x02\x12\t\n\x05TORV2\x10\x03\x12\t\n\x05TORV3\x10\x04\x42\n\n\x08_addressB\x07\n\x05_portB\t\n\x07_socket\"H\n\x10ListpeersRequest\x12\x0f\n\x02id\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x12\x12\n\x05level\x18\x02 \x01(\tH\x01\x88\x01\x01\x42\x05\n\x03_idB\x08\n\x06_level\"7\n\x11ListpeersResponse\x12\"\n\x05peers\x18\x01 \x03(\x0b\x32\x13.cln.ListpeersPeers\"\x8e\x02\n\x0eListpeersPeers\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x11\n\tconnected\x18\x02 \x01(\x08\x12\x19\n\x0cnum_channels\x18\x08 \x01(\rH\x00\x88\x01\x01\x12#\n\x03log\x18\x03 \x03(\x0b\x32\x16.cln.ListpeersPeersLog\x12-\n\x08\x63hannels\x18\x04 \x03(\x0b\x32\x1b.cln.ListpeersPeersChannels\x12\x0f\n\x07netaddr\x18\x05 \x03(\t\x12\x18\n\x0bremote_addr\x18\x07 \x01(\tH\x01\x88\x01\x01\x12\x15\n\x08\x66\x65\x61tures\x18\x06 \x01(\x0cH\x02\x88\x01\x01\x42\x0f\n\r_num_channelsB\x0e\n\x0c_remote_addrB\x0b\n\t_features\"\xfd\x02\n\x11ListpeersPeersLog\x12?\n\titem_type\x18\x01 \x01(\x0e\x32,.cln.ListpeersPeersLog.ListpeersPeersLogType\x12\x18\n\x0bnum_skipped\x18\x02 \x01(\rH\x00\x88\x01\x01\x12\x11\n\x04time\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x13\n\x06source\x18\x04 \x01(\tH\x02\x88\x01\x01\x12\x10\n\x03log\x18\x05 \x01(\tH\x03\x88\x01\x01\x12\x14\n\x07node_id\x18\x06 \x01(\x0cH\x04\x88\x01\x01\x12\x11\n\x04\x64\x61ta\x18\x07 \x01(\x0cH\x05\x88\x01\x01\"i\n\x15ListpeersPeersLogType\x12\x0b\n\x07SKIPPED\x10\x00\x12\n\n\x06\x42ROKEN\x10\x01\x12\x0b\n\x07UNUSUAL\x10\x02\x12\x08\n\x04INFO\x10\x03\x12\t\n\x05\x44\x45\x42UG\x10\x04\x12\t\n\x05IO_IN\x10\x05\x12\n\n\x06IO_OUT\x10\x06\x42\x0e\n\x0c_num_skippedB\x07\n\x05_timeB\t\n\x07_sourceB\x06\n\x04_logB\n\n\x08_node_idB\x07\n\x05_data\"\x95\x18\n\x16ListpeersPeersChannels\x12\x46\n\x05state\x18\x01 \x01(\x0e\x32\x37.cln.ListpeersPeersChannels.ListpeersPeersChannelsState\x12\x19\n\x0cscratch_txid\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12\x38\n\x07\x66\x65\x65rate\x18\x03 \x01(\x0b\x32\".cln.ListpeersPeersChannelsFeerateH\x01\x88\x01\x01\x12\x12\n\x05owner\x18\x04 \x01(\tH\x02\x88\x01\x01\x12\x1d\n\x10short_channel_id\x18\x05 \x01(\tH\x03\x88\x01\x01\x12\x17\n\nchannel_id\x18\x06 \x01(\x0cH\x04\x88\x01\x01\x12\x19\n\x0c\x66unding_txid\x18\x07 \x01(\x0cH\x05\x88\x01\x01\x12\x1b\n\x0e\x66unding_outnum\x18\x08 \x01(\rH\x06\x88\x01\x01\x12\x1c\n\x0finitial_feerate\x18\t \x01(\tH\x07\x88\x01\x01\x12\x19\n\x0clast_feerate\x18\n \x01(\tH\x08\x88\x01\x01\x12\x19\n\x0cnext_feerate\x18\x0b \x01(\tH\t\x88\x01\x01\x12\x1a\n\rnext_fee_step\x18\x0c \x01(\rH\n\x88\x01\x01\x12\x35\n\x08inflight\x18\r \x03(\x0b\x32#.cln.ListpeersPeersChannelsInflight\x12\x15\n\x08\x63lose_to\x18\x0e \x01(\x0cH\x0b\x88\x01\x01\x12\x14\n\x07private\x18\x0f \x01(\x08H\x0c\x88\x01\x01\x12 \n\x06opener\x18\x10 \x01(\x0e\x32\x10.cln.ChannelSide\x12%\n\x06\x63loser\x18\x11 \x01(\x0e\x32\x10.cln.ChannelSideH\r\x88\x01\x01\x12\x10\n\x08\x66\x65\x61tures\x18\x12 \x03(\t\x12\x38\n\x07\x66unding\x18\x13 \x01(\x0b\x32\".cln.ListpeersPeersChannelsFundingH\x0e\x88\x01\x01\x12$\n\nto_us_msat\x18\x14 \x01(\x0b\x32\x0b.cln.AmountH\x0f\x88\x01\x01\x12(\n\x0emin_to_us_msat\x18\x15 \x01(\x0b\x32\x0b.cln.AmountH\x10\x88\x01\x01\x12(\n\x0emax_to_us_msat\x18\x16 \x01(\x0b\x32\x0b.cln.AmountH\x11\x88\x01\x01\x12$\n\ntotal_msat\x18\x17 \x01(\x0b\x32\x0b.cln.AmountH\x12\x88\x01\x01\x12\'\n\rfee_base_msat\x18\x18 \x01(\x0b\x32\x0b.cln.AmountH\x13\x88\x01\x01\x12(\n\x1b\x66\x65\x65_proportional_millionths\x18\x19 \x01(\rH\x14\x88\x01\x01\x12)\n\x0f\x64ust_limit_msat\x18\x1a \x01(\x0b\x32\x0b.cln.AmountH\x15\x88\x01\x01\x12\x30\n\x16max_total_htlc_in_msat\x18\x1b \x01(\x0b\x32\x0b.cln.AmountH\x16\x88\x01\x01\x12,\n\x12their_reserve_msat\x18\x1c \x01(\x0b\x32\x0b.cln.AmountH\x17\x88\x01\x01\x12*\n\x10our_reserve_msat\x18\x1d \x01(\x0b\x32\x0b.cln.AmountH\x18\x88\x01\x01\x12(\n\x0espendable_msat\x18\x1e \x01(\x0b\x32\x0b.cln.AmountH\x19\x88\x01\x01\x12)\n\x0freceivable_msat\x18\x1f \x01(\x0b\x32\x0b.cln.AmountH\x1a\x88\x01\x01\x12.\n\x14minimum_htlc_in_msat\x18 \x01(\x0b\x32\x0b.cln.AmountH\x1b\x88\x01\x01\x12/\n\x15minimum_htlc_out_msat\x18\x30 \x01(\x0b\x32\x0b.cln.AmountH\x1c\x88\x01\x01\x12/\n\x15maximum_htlc_out_msat\x18\x31 \x01(\x0b\x32\x0b.cln.AmountH\x1d\x88\x01\x01\x12 \n\x13their_to_self_delay\x18! \x01(\rH\x1e\x88\x01\x01\x12\x1e\n\x11our_to_self_delay\x18\" \x01(\rH\x1f\x88\x01\x01\x12\x1f\n\x12max_accepted_htlcs\x18# \x01(\rH \x88\x01\x01\x12\x34\n\x05\x61lias\x18\x32 \x01(\x0b\x32 .cln.ListpeersPeersChannelsAliasH!\x88\x01\x01\x12\x0e\n\x06status\x18% \x03(\t\x12 \n\x13in_payments_offered\x18& \x01(\x04H\"\x88\x01\x01\x12)\n\x0fin_offered_msat\x18\' \x01(\x0b\x32\x0b.cln.AmountH#\x88\x01\x01\x12\"\n\x15in_payments_fulfilled\x18( \x01(\x04H$\x88\x01\x01\x12+\n\x11in_fulfilled_msat\x18) \x01(\x0b\x32\x0b.cln.AmountH%\x88\x01\x01\x12!\n\x14out_payments_offered\x18* \x01(\x04H&\x88\x01\x01\x12*\n\x10out_offered_msat\x18+ \x01(\x0b\x32\x0b.cln.AmountH\'\x88\x01\x01\x12#\n\x16out_payments_fulfilled\x18, \x01(\x04H(\x88\x01\x01\x12,\n\x12out_fulfilled_msat\x18- \x01(\x0b\x32\x0b.cln.AmountH)\x88\x01\x01\x12/\n\x05htlcs\x18. \x03(\x0b\x32 .cln.ListpeersPeersChannelsHtlcs\x12\x1a\n\rclose_to_addr\x18/ \x01(\tH*\x88\x01\x01\"\xe0\x02\n\x1bListpeersPeersChannelsState\x12\x0c\n\x08OPENINGD\x10\x00\x12\x1c\n\x18\x43HANNELD_AWAITING_LOCKIN\x10\x01\x12\x13\n\x0f\x43HANNELD_NORMAL\x10\x02\x12\x1a\n\x16\x43HANNELD_SHUTTING_DOWN\x10\x03\x12\x18\n\x14\x43LOSINGD_SIGEXCHANGE\x10\x04\x12\x15\n\x11\x43LOSINGD_COMPLETE\x10\x05\x12\x17\n\x13\x41WAITING_UNILATERAL\x10\x06\x12\x16\n\x12\x46UNDING_SPEND_SEEN\x10\x07\x12\x0b\n\x07ONCHAIN\x10\x08\x12\x17\n\x13\x44UALOPEND_OPEN_INIT\x10\t\x12\x1d\n\x19\x44UALOPEND_AWAITING_LOCKIN\x10\n\x12\x1c\n\x18\x44UALOPEND_OPEN_COMMITTED\x10\x0b\x12\x1f\n\x1b\x44UALOPEND_OPEN_COMMIT_READY\x10\x0c\x42\x0f\n\r_scratch_txidB\n\n\x08_feerateB\x08\n\x06_ownerB\x13\n\x11_short_channel_idB\r\n\x0b_channel_idB\x0f\n\r_funding_txidB\x11\n\x0f_funding_outnumB\x12\n\x10_initial_feerateB\x0f\n\r_last_feerateB\x0f\n\r_next_feerateB\x10\n\x0e_next_fee_stepB\x0b\n\t_close_toB\n\n\x08_privateB\t\n\x07_closerB\n\n\x08_fundingB\r\n\x0b_to_us_msatB\x11\n\x0f_min_to_us_msatB\x11\n\x0f_max_to_us_msatB\r\n\x0b_total_msatB\x10\n\x0e_fee_base_msatB\x1e\n\x1c_fee_proportional_millionthsB\x12\n\x10_dust_limit_msatB\x19\n\x17_max_total_htlc_in_msatB\x15\n\x13_their_reserve_msatB\x13\n\x11_our_reserve_msatB\x11\n\x0f_spendable_msatB\x12\n\x10_receivable_msatB\x17\n\x15_minimum_htlc_in_msatB\x18\n\x16_minimum_htlc_out_msatB\x18\n\x16_maximum_htlc_out_msatB\x16\n\x14_their_to_self_delayB\x14\n\x12_our_to_self_delayB\x15\n\x13_max_accepted_htlcsB\x08\n\x06_aliasB\x16\n\x14_in_payments_offeredB\x12\n\x10_in_offered_msatB\x18\n\x16_in_payments_fulfilledB\x14\n\x12_in_fulfilled_msatB\x17\n\x15_out_payments_offeredB\x13\n\x11_out_offered_msatB\x19\n\x17_out_payments_fulfilledB\x15\n\x13_out_fulfilled_msatB\x10\n\x0e_close_to_addr\"=\n\x1dListpeersPeersChannelsFeerate\x12\r\n\x05perkw\x18\x01 \x01(\r\x12\r\n\x05perkb\x18\x02 \x01(\r\"\xf3\x01\n\x1eListpeersPeersChannelsInflight\x12\x14\n\x0c\x66unding_txid\x18\x01 \x01(\x0c\x12\x16\n\x0e\x66unding_outnum\x18\x02 \x01(\r\x12\x0f\n\x07\x66\x65\x65rate\x18\x03 \x01(\t\x12\'\n\x12total_funding_msat\x18\x04 \x01(\x0b\x32\x0b.cln.Amount\x12%\n\x10our_funding_msat\x18\x05 \x01(\x0b\x32\x0b.cln.Amount\x12\x1a\n\rsplice_amount\x18\x07 \x01(\x12H\x00\x88\x01\x01\x12\x14\n\x0cscratch_txid\x18\x06 \x01(\x0c\x42\x10\n\x0e_splice_amount\"\x9b\x02\n\x1dListpeersPeersChannelsFunding\x12%\n\x0bpushed_msat\x18\x03 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12%\n\x10local_funds_msat\x18\x04 \x01(\x0b\x32\x0b.cln.Amount\x12&\n\x11remote_funds_msat\x18\x07 \x01(\x0b\x32\x0b.cln.Amount\x12\'\n\rfee_paid_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x01\x88\x01\x01\x12\'\n\rfee_rcvd_msat\x18\x06 \x01(\x0b\x32\x0b.cln.AmountH\x02\x88\x01\x01\x42\x0e\n\x0c_pushed_msatB\x10\n\x0e_fee_paid_msatB\x10\n\x0e_fee_rcvd_msat\"[\n\x1bListpeersPeersChannelsAlias\x12\x12\n\x05local\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06remote\x18\x02 \x01(\tH\x01\x88\x01\x01\x42\x08\n\x06_localB\t\n\x07_remote\"\xf1\x02\n\x1bListpeersPeersChannelsHtlcs\x12X\n\tdirection\x18\x01 \x01(\x0e\x32\x45.cln.ListpeersPeersChannelsHtlcs.ListpeersPeersChannelsHtlcsDirection\x12\n\n\x02id\x18\x02 \x01(\x04\x12 \n\x0b\x61mount_msat\x18\x03 \x01(\x0b\x32\x0b.cln.Amount\x12\x0e\n\x06\x65xpiry\x18\x04 \x01(\r\x12\x14\n\x0cpayment_hash\x18\x05 \x01(\x0c\x12\x1a\n\rlocal_trimmed\x18\x06 \x01(\x08H\x00\x88\x01\x01\x12\x13\n\x06status\x18\x07 \x01(\tH\x01\x88\x01\x01\x12\x1d\n\x05state\x18\x08 \x01(\x0e\x32\x0e.cln.HtlcState\"7\n$ListpeersPeersChannelsHtlcsDirection\x12\x06\n\x02IN\x10\x00\x12\x07\n\x03OUT\x10\x01\x42\x10\n\x0e_local_trimmedB\t\n\x07_status\"0\n\x10ListfundsRequest\x12\x12\n\x05spent\x18\x01 \x01(\x08H\x00\x88\x01\x01\x42\x08\n\x06_spent\"e\n\x11ListfundsResponse\x12&\n\x07outputs\x18\x01 \x03(\x0b\x32\x15.cln.ListfundsOutputs\x12(\n\x08\x63hannels\x18\x02 \x03(\x0b\x32\x16.cln.ListfundsChannels\"\x83\x03\n\x10ListfundsOutputs\x12\x0c\n\x04txid\x18\x01 \x01(\x0c\x12\x0e\n\x06output\x18\x02 \x01(\r\x12 \n\x0b\x61mount_msat\x18\x03 \x01(\x0b\x32\x0b.cln.Amount\x12\x14\n\x0cscriptpubkey\x18\x04 \x01(\x0c\x12\x14\n\x07\x61\x64\x64ress\x18\x05 \x01(\tH\x00\x88\x01\x01\x12\x19\n\x0credeemscript\x18\x06 \x01(\x0cH\x01\x88\x01\x01\x12<\n\x06status\x18\x07 \x01(\x0e\x32,.cln.ListfundsOutputs.ListfundsOutputsStatus\x12\x10\n\x08reserved\x18\t \x01(\x08\x12\x18\n\x0b\x62lockheight\x18\x08 \x01(\rH\x02\x88\x01\x01\"Q\n\x16ListfundsOutputsStatus\x12\x0f\n\x0bUNCONFIRMED\x10\x00\x12\r\n\tCONFIRMED\x10\x01\x12\t\n\x05SPENT\x10\x02\x12\x0c\n\x08IMMATURE\x10\x03\x42\n\n\x08_addressB\x0f\n\r_redeemscriptB\x0e\n\x0c_blockheight\"\xab\x02\n\x11ListfundsChannels\x12\x0f\n\x07peer_id\x18\x01 \x01(\x0c\x12$\n\x0four_amount_msat\x18\x02 \x01(\x0b\x32\x0b.cln.Amount\x12 \n\x0b\x61mount_msat\x18\x03 \x01(\x0b\x32\x0b.cln.Amount\x12\x14\n\x0c\x66unding_txid\x18\x04 \x01(\x0c\x12\x16\n\x0e\x66unding_output\x18\x05 \x01(\r\x12\x11\n\tconnected\x18\x06 \x01(\x08\x12 \n\x05state\x18\x07 \x01(\x0e\x32\x11.cln.ChannelState\x12\x17\n\nchannel_id\x18\t \x01(\x0cH\x00\x88\x01\x01\x12\x1d\n\x10short_channel_id\x18\x08 \x01(\tH\x01\x88\x01\x01\x42\r\n\x0b_channel_idB\x13\n\x11_short_channel_id\"\xdd\x02\n\x0eSendpayRequest\x12 \n\x05route\x18\x01 \x03(\x0b\x32\x11.cln.SendpayRoute\x12\x14\n\x0cpayment_hash\x18\x02 \x01(\x0c\x12\x12\n\x05label\x18\x03 \x01(\tH\x00\x88\x01\x01\x12%\n\x0b\x61mount_msat\x18\n \x01(\x0b\x32\x0b.cln.AmountH\x01\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x05 \x01(\tH\x02\x88\x01\x01\x12\x1b\n\x0epayment_secret\x18\x06 \x01(\x0cH\x03\x88\x01\x01\x12\x13\n\x06partid\x18\x07 \x01(\rH\x04\x88\x01\x01\x12\x1a\n\rlocalinvreqid\x18\x0b \x01(\x0cH\x05\x88\x01\x01\x12\x14\n\x07groupid\x18\t \x01(\x04H\x06\x88\x01\x01\x42\x08\n\x06_labelB\x0e\n\x0c_amount_msatB\t\n\x07_bolt11B\x11\n\x0f_payment_secretB\t\n\x07_partidB\x10\n\x0e_localinvreqidB\n\n\x08_groupid\"\xad\x05\n\x0fSendpayResponse\x12\x1a\n\rcreated_index\x18\x10 \x01(\x04H\x00\x88\x01\x01\x12\x1a\n\rupdated_index\x18\x11 \x01(\x04H\x01\x88\x01\x01\x12\n\n\x02id\x18\x01 \x01(\x04\x12\x14\n\x07groupid\x18\x02 \x01(\x04H\x02\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12\x32\n\x06status\x18\x04 \x01(\x0e\x32\".cln.SendpayResponse.SendpayStatus\x12%\n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x03\x88\x01\x01\x12\x18\n\x0b\x64\x65stination\x18\x06 \x01(\x0cH\x04\x88\x01\x01\x12\x12\n\ncreated_at\x18\x07 \x01(\x04\x12\x19\n\x0c\x63ompleted_at\x18\x0f \x01(\x04H\x05\x88\x01\x01\x12%\n\x10\x61mount_sent_msat\x18\x08 \x01(\x0b\x32\x0b.cln.Amount\x12\x12\n\x05label\x18\t \x01(\tH\x06\x88\x01\x01\x12\x13\n\x06partid\x18\n \x01(\x04H\x07\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x0b \x01(\tH\x08\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x0c \x01(\tH\t\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\r \x01(\x0cH\n\x88\x01\x01\x12\x14\n\x07message\x18\x0e \x01(\tH\x0b\x88\x01\x01\"*\n\rSendpayStatus\x12\x0b\n\x07PENDING\x10\x00\x12\x0c\n\x08\x43OMPLETE\x10\x01\x42\x10\n\x0e_created_indexB\x10\n\x0e_updated_indexB\n\n\x08_groupidB\x0e\n\x0c_amount_msatB\x0e\n\x0c_destinationB\x0f\n\r_completed_atB\x08\n\x06_labelB\t\n\x07_partidB\t\n\x07_bolt11B\t\n\x07_bolt12B\x13\n\x11_payment_preimageB\n\n\x08_message\"\\\n\x0cSendpayRoute\x12 \n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.Amount\x12\n\n\x02id\x18\x02 \x01(\x0c\x12\r\n\x05\x64\x65lay\x18\x03 \x01(\r\x12\x0f\n\x07\x63hannel\x18\x04 \x01(\t\"\x93\x01\n\x13ListchannelsRequest\x12\x1d\n\x10short_channel_id\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06source\x18\x02 \x01(\x0cH\x01\x88\x01\x01\x12\x18\n\x0b\x64\x65stination\x18\x03 \x01(\x0cH\x02\x88\x01\x01\x42\x13\n\x11_short_channel_idB\t\n\x07_sourceB\x0e\n\x0c_destination\"C\n\x14ListchannelsResponse\x12+\n\x08\x63hannels\x18\x01 \x03(\x0b\x32\x19.cln.ListchannelsChannels\"\xb3\x03\n\x14ListchannelsChannels\x12\x0e\n\x06source\x18\x01 \x01(\x0c\x12\x13\n\x0b\x64\x65stination\x18\x02 \x01(\x0c\x12\x18\n\x10short_channel_id\x18\x03 \x01(\t\x12\x11\n\tdirection\x18\x10 \x01(\r\x12\x0e\n\x06public\x18\x04 \x01(\x08\x12 \n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.Amount\x12\x15\n\rmessage_flags\x18\x06 \x01(\r\x12\x15\n\rchannel_flags\x18\x07 \x01(\r\x12\x0e\n\x06\x61\x63tive\x18\x08 \x01(\x08\x12\x13\n\x0blast_update\x18\t \x01(\r\x12\x1d\n\x15\x62\x61se_fee_millisatoshi\x18\n \x01(\r\x12\x19\n\x11\x66\x65\x65_per_millionth\x18\x0b \x01(\r\x12\r\n\x05\x64\x65lay\x18\x0c \x01(\r\x12&\n\x11htlc_minimum_msat\x18\r \x01(\x0b\x32\x0b.cln.Amount\x12+\n\x11htlc_maximum_msat\x18\x0e \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12\x10\n\x08\x66\x65\x61tures\x18\x0f \x01(\x0c\x42\x14\n\x12_htlc_maximum_msat\"#\n\x10\x41\x64\x64gossipRequest\x12\x0f\n\x07message\x18\x01 \x01(\x0c\"\x13\n\x11\x41\x64\x64gossipResponse\"o\n\x17\x41utocleaninvoiceRequest\x12\x17\n\nexpired_by\x18\x01 \x01(\x04H\x00\x88\x01\x01\x12\x1a\n\rcycle_seconds\x18\x02 \x01(\x04H\x01\x88\x01\x01\x42\r\n\x0b_expired_byB\x10\n\x0e_cycle_seconds\"\x81\x01\n\x18\x41utocleaninvoiceResponse\x12\x0f\n\x07\x65nabled\x18\x01 \x01(\x08\x12\x17\n\nexpired_by\x18\x02 \x01(\x04H\x00\x88\x01\x01\x12\x1a\n\rcycle_seconds\x18\x03 \x01(\x04H\x01\x88\x01\x01\x42\r\n\x0b_expired_byB\x10\n\x0e_cycle_seconds\"U\n\x13\x43heckmessageRequest\x12\x0f\n\x07message\x18\x01 \x01(\t\x12\r\n\x05zbase\x18\x02 \x01(\t\x12\x13\n\x06pubkey\x18\x03 \x01(\x0cH\x00\x88\x01\x01\x42\t\n\x07_pubkey\"8\n\x14\x43heckmessageResponse\x12\x10\n\x08verified\x18\x01 \x01(\x08\x12\x0e\n\x06pubkey\x18\x02 \x01(\x0c\"\xcb\x02\n\x0c\x43loseRequest\x12\n\n\x02id\x18\x01 \x01(\t\x12\x1e\n\x11unilateraltimeout\x18\x02 \x01(\rH\x00\x88\x01\x01\x12\x18\n\x0b\x64\x65stination\x18\x03 \x01(\tH\x01\x88\x01\x01\x12!\n\x14\x66\x65\x65_negotiation_step\x18\x04 \x01(\tH\x02\x88\x01\x01\x12)\n\rwrong_funding\x18\x05 \x01(\x0b\x32\r.cln.OutpointH\x03\x88\x01\x01\x12\x1f\n\x12\x66orce_lease_closed\x18\x06 \x01(\x08H\x04\x88\x01\x01\x12\x1e\n\x08\x66\x65\x65range\x18\x07 \x03(\x0b\x32\x0c.cln.FeerateB\x14\n\x12_unilateraltimeoutB\x0e\n\x0c_destinationB\x17\n\x15_fee_negotiation_stepB\x10\n\x0e_wrong_fundingB\x15\n\x13_force_lease_closed\"\xab\x01\n\rCloseResponse\x12/\n\titem_type\x18\x01 \x01(\x0e\x32\x1c.cln.CloseResponse.CloseType\x12\x0f\n\x02tx\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12\x11\n\x04txid\x18\x03 \x01(\x0cH\x01\x88\x01\x01\"5\n\tCloseType\x12\n\n\x06MUTUAL\x10\x00\x12\x0e\n\nUNILATERAL\x10\x01\x12\x0c\n\x08UNOPENED\x10\x02\x42\x05\n\x03_txB\x07\n\x05_txid\"T\n\x0e\x43onnectRequest\x12\n\n\x02id\x18\x01 \x01(\t\x12\x11\n\x04host\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x11\n\x04port\x18\x03 \x01(\rH\x01\x88\x01\x01\x42\x07\n\x05_hostB\x07\n\x05_port\"\xb4\x01\n\x0f\x43onnectResponse\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x10\n\x08\x66\x65\x61tures\x18\x02 \x01(\x0c\x12\x38\n\tdirection\x18\x03 \x01(\x0e\x32%.cln.ConnectResponse.ConnectDirection\x12$\n\x07\x61\x64\x64ress\x18\x04 \x01(\x0b\x32\x13.cln.ConnectAddress\"#\n\x10\x43onnectDirection\x12\x06\n\x02IN\x10\x00\x12\x07\n\x03OUT\x10\x01\"\xfb\x01\n\x0e\x43onnectAddress\x12\x39\n\titem_type\x18\x01 \x01(\x0e\x32&.cln.ConnectAddress.ConnectAddressType\x12\x13\n\x06socket\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x14\n\x07\x61\x64\x64ress\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x11\n\x04port\x18\x04 \x01(\rH\x02\x88\x01\x01\"P\n\x12\x43onnectAddressType\x12\x10\n\x0cLOCAL_SOCKET\x10\x00\x12\x08\n\x04IPV4\x10\x01\x12\x08\n\x04IPV6\x10\x02\x12\t\n\x05TORV2\x10\x03\x12\t\n\x05TORV3\x10\x04\x42\t\n\x07_socketB\n\n\x08_addressB\x07\n\x05_port\"J\n\x14\x43reateinvoiceRequest\x12\x11\n\tinvstring\x18\x01 \x01(\t\x12\r\n\x05label\x18\x02 \x01(\t\x12\x10\n\x08preimage\x18\x03 \x01(\x0c\"\xfe\x05\n\x15\x43reateinvoiceResponse\x12\r\n\x05label\x18\x01 \x01(\t\x12\x13\n\x06\x62olt11\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x04 \x01(\x0c\x12%\n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x02\x88\x01\x01\x12>\n\x06status\x18\x06 \x01(\x0e\x32..cln.CreateinvoiceResponse.CreateinvoiceStatus\x12\x13\n\x0b\x64\x65scription\x18\x07 \x01(\t\x12\x12\n\nexpires_at\x18\x08 \x01(\x04\x12\x1a\n\rcreated_index\x18\x10 \x01(\x04H\x03\x88\x01\x01\x12\x16\n\tpay_index\x18\t \x01(\x04H\x04\x88\x01\x01\x12.\n\x14\x61mount_received_msat\x18\n \x01(\x0b\x32\x0b.cln.AmountH\x05\x88\x01\x01\x12\x14\n\x07paid_at\x18\x0b \x01(\x04H\x06\x88\x01\x01\x12;\n\rpaid_outpoint\x18\x11 \x01(\x0b\x32\x1f.cln.CreateinvoicePaid_outpointH\x07\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\x0c \x01(\x0cH\x08\x88\x01\x01\x12\x1b\n\x0elocal_offer_id\x18\r \x01(\x0cH\t\x88\x01\x01\x12\x1e\n\x11invreq_payer_note\x18\x0f \x01(\tH\n\x88\x01\x01\"8\n\x13\x43reateinvoiceStatus\x12\x08\n\x04PAID\x10\x00\x12\x0b\n\x07\x45XPIRED\x10\x01\x12\n\n\x06UNPAID\x10\x02\x42\t\n\x07_bolt11B\t\n\x07_bolt12B\x0e\n\x0c_amount_msatB\x10\n\x0e_created_indexB\x0c\n\n_pay_indexB\x17\n\x15_amount_received_msatB\n\n\x08_paid_atB\x10\n\x0e_paid_outpointB\x13\n\x11_payment_preimageB\x11\n\x0f_local_offer_idB\x14\n\x12_invreq_payer_note\"X\n\x1a\x43reateinvoicePaid_outpoint\x12\x11\n\x04txid\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x12\x13\n\x06outnum\x18\x02 \x01(\rH\x01\x88\x01\x01\x42\x07\n\x05_txidB\t\n\x07_outnum\"\xb4\x02\n\x10\x44\x61tastoreRequest\x12\x0b\n\x03key\x18\x05 \x03(\t\x12\x13\n\x06string\x18\x06 \x01(\tH\x00\x88\x01\x01\x12\x10\n\x03hex\x18\x02 \x01(\x0cH\x01\x88\x01\x01\x12\x36\n\x04mode\x18\x03 \x01(\x0e\x32#.cln.DatastoreRequest.DatastoreModeH\x02\x88\x01\x01\x12\x17\n\ngeneration\x18\x04 \x01(\x04H\x03\x88\x01\x01\"p\n\rDatastoreMode\x12\x0f\n\x0bMUST_CREATE\x10\x00\x12\x10\n\x0cMUST_REPLACE\x10\x01\x12\x15\n\x11\x43REATE_OR_REPLACE\x10\x02\x12\x0f\n\x0bMUST_APPEND\x10\x03\x12\x14\n\x10\x43REATE_OR_APPEND\x10\x04\x42\t\n\x07_stringB\x06\n\x04_hexB\x07\n\x05_modeB\r\n\x0b_generation\"\x82\x01\n\x11\x44\x61tastoreResponse\x12\x0b\n\x03key\x18\x05 \x03(\t\x12\x17\n\ngeneration\x18\x02 \x01(\x04H\x00\x88\x01\x01\x12\x10\n\x03hex\x18\x03 \x01(\x0cH\x01\x88\x01\x01\x12\x13\n\x06string\x18\x04 \x01(\tH\x02\x88\x01\x01\x42\r\n\x0b_generationB\x06\n\x04_hexB\t\n\x07_string\"\x17\n\x15\x44\x61tastoreusageRequest\"k\n\x16\x44\x61tastoreusageResponse\x12>\n\x0e\x64\x61tastoreusage\x18\x01 \x01(\x0b\x32!.cln.DatastoreusageDatastoreusageH\x00\x88\x01\x01\x42\x11\n\x0f_datastoreusage\"b\n\x1c\x44\x61tastoreusageDatastoreusage\x12\x10\n\x03key\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x18\n\x0btotal_bytes\x18\x02 \x01(\x04H\x01\x88\x01\x01\x42\x06\n\x04_keyB\x0e\n\x0c_total_bytes\"\x9d\x01\n\x12\x43reateonionRequest\x12\"\n\x04hops\x18\x01 \x03(\x0b\x32\x14.cln.CreateonionHops\x12\x11\n\tassocdata\x18\x02 \x01(\x0c\x12\x18\n\x0bsession_key\x18\x03 \x01(\x0cH\x00\x88\x01\x01\x12\x17\n\nonion_size\x18\x04 \x01(\rH\x01\x88\x01\x01\x42\x0e\n\x0c_session_keyB\r\n\x0b_onion_size\"<\n\x13\x43reateonionResponse\x12\r\n\x05onion\x18\x01 \x01(\x0c\x12\x16\n\x0eshared_secrets\x18\x02 \x03(\x0c\"2\n\x0f\x43reateonionHops\x12\x0e\n\x06pubkey\x18\x01 \x01(\x0c\x12\x0f\n\x07payload\x18\x02 \x01(\x0c\"J\n\x13\x44\x65ldatastoreRequest\x12\x0b\n\x03key\x18\x03 \x03(\t\x12\x17\n\ngeneration\x18\x02 \x01(\x04H\x00\x88\x01\x01\x42\r\n\x0b_generation\"\x85\x01\n\x14\x44\x65ldatastoreResponse\x12\x0b\n\x03key\x18\x05 \x03(\t\x12\x17\n\ngeneration\x18\x02 \x01(\x04H\x00\x88\x01\x01\x12\x10\n\x03hex\x18\x03 \x01(\x0cH\x01\x88\x01\x01\x12\x13\n\x06string\x18\x04 \x01(\tH\x02\x88\x01\x01\x42\r\n\x0b_generationB\x06\n\x04_hexB\t\n\x07_string\"H\n\x18\x44\x65lexpiredinvoiceRequest\x12\x1a\n\rmaxexpirytime\x18\x01 \x01(\x04H\x00\x88\x01\x01\x42\x10\n\x0e_maxexpirytime\"\x1b\n\x19\x44\x65lexpiredinvoiceResponse\"\xb6\x01\n\x11\x44\x65linvoiceRequest\x12\r\n\x05label\x18\x01 \x01(\t\x12\x37\n\x06status\x18\x02 \x01(\x0e\x32\'.cln.DelinvoiceRequest.DelinvoiceStatus\x12\x15\n\x08\x64\x65sconly\x18\x03 \x01(\x08H\x00\x88\x01\x01\"5\n\x10\x44\x65linvoiceStatus\x12\x08\n\x04PAID\x10\x00\x12\x0b\n\x07\x45XPIRED\x10\x01\x12\n\n\x06UNPAID\x10\x02\x42\x0b\n\t_desconly\"\xa1\x04\n\x12\x44\x65linvoiceResponse\x12\r\n\x05label\x18\x01 \x01(\t\x12\x13\n\x06\x62olt11\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x03 \x01(\tH\x01\x88\x01\x01\x12%\n\x0b\x61mount_msat\x18\x04 \x01(\x0b\x32\x0b.cln.AmountH\x02\x88\x01\x01\x12\x18\n\x0b\x64\x65scription\x18\x05 \x01(\tH\x03\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x06 \x01(\x0c\x12\x1a\n\rcreated_index\x18\x0c \x01(\x04H\x04\x88\x01\x01\x12\x1a\n\rupdated_index\x18\r \x01(\x04H\x05\x88\x01\x01\x12\x38\n\x06status\x18\x07 \x01(\x0e\x32(.cln.DelinvoiceResponse.DelinvoiceStatus\x12\x12\n\nexpires_at\x18\x08 \x01(\x04\x12\x1b\n\x0elocal_offer_id\x18\t \x01(\x0cH\x06\x88\x01\x01\x12\x1e\n\x11invreq_payer_note\x18\x0b \x01(\tH\x07\x88\x01\x01\"5\n\x10\x44\x65linvoiceStatus\x12\x08\n\x04PAID\x10\x00\x12\x0b\n\x07\x45XPIRED\x10\x01\x12\n\n\x06UNPAID\x10\x02\x42\t\n\x07_bolt11B\t\n\x07_bolt12B\x0e\n\x0c_amount_msatB\x0e\n\x0c_descriptionB\x10\n\x0e_created_indexB\x10\n\x0e_updated_indexB\x11\n\x0f_local_offer_idB\x14\n\x12_invreq_payer_note\"\xfa\x01\n\x0eInvoiceRequest\x12%\n\x0b\x61mount_msat\x18\n \x01(\x0b\x32\x10.cln.AmountOrAny\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\r\n\x05label\x18\x03 \x01(\t\x12\x13\n\x06\x65xpiry\x18\x07 \x01(\x04H\x00\x88\x01\x01\x12\x11\n\tfallbacks\x18\x04 \x03(\t\x12\x15\n\x08preimage\x18\x05 \x01(\x0cH\x01\x88\x01\x01\x12\x11\n\x04\x63ltv\x18\x06 \x01(\rH\x02\x88\x01\x01\x12\x19\n\x0c\x64\x65schashonly\x18\t \x01(\x08H\x03\x88\x01\x01\x42\t\n\x07_expiryB\x0b\n\t_preimageB\x07\n\x05_cltvB\x0f\n\r_deschashonly\"\x95\x03\n\x0fInvoiceResponse\x12\x0e\n\x06\x62olt11\x18\x01 \x01(\t\x12\x14\n\x0cpayment_hash\x18\x02 \x01(\x0c\x12\x16\n\x0epayment_secret\x18\x03 \x01(\x0c\x12\x12\n\nexpires_at\x18\x04 \x01(\x04\x12\x1a\n\rcreated_index\x18\n \x01(\x04H\x00\x88\x01\x01\x12\x1d\n\x10warning_capacity\x18\x05 \x01(\tH\x01\x88\x01\x01\x12\x1c\n\x0fwarning_offline\x18\x06 \x01(\tH\x02\x88\x01\x01\x12\x1d\n\x10warning_deadends\x18\x07 \x01(\tH\x03\x88\x01\x01\x12#\n\x16warning_private_unused\x18\x08 \x01(\tH\x04\x88\x01\x01\x12\x18\n\x0bwarning_mpp\x18\t \x01(\tH\x05\x88\x01\x01\x42\x10\n\x0e_created_indexB\x13\n\x11_warning_capacityB\x12\n\x10_warning_offlineB\x13\n\x11_warning_deadendsB\x19\n\x17_warning_private_unusedB\x0e\n\x0c_warning_mpp\"#\n\x14ListdatastoreRequest\x12\x0b\n\x03key\x18\x02 \x03(\t\"G\n\x15ListdatastoreResponse\x12.\n\tdatastore\x18\x01 \x03(\x0b\x32\x1b.cln.ListdatastoreDatastore\"\x87\x01\n\x16ListdatastoreDatastore\x12\x0b\n\x03key\x18\x01 \x03(\t\x12\x17\n\ngeneration\x18\x02 \x01(\x04H\x00\x88\x01\x01\x12\x10\n\x03hex\x18\x03 \x01(\x0cH\x01\x88\x01\x01\x12\x13\n\x06string\x18\x04 \x01(\tH\x02\x88\x01\x01\x42\r\n\x0b_generationB\x06\n\x04_hexB\t\n\x07_string\"\xde\x02\n\x13ListinvoicesRequest\x12\x12\n\x05label\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x16\n\tinvstring\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x19\n\x0cpayment_hash\x18\x03 \x01(\x0cH\x02\x88\x01\x01\x12\x15\n\x08offer_id\x18\x04 \x01(\tH\x03\x88\x01\x01\x12>\n\x05index\x18\x05 \x01(\x0e\x32*.cln.ListinvoicesRequest.ListinvoicesIndexH\x04\x88\x01\x01\x12\x12\n\x05start\x18\x06 \x01(\x04H\x05\x88\x01\x01\x12\x12\n\x05limit\x18\x07 \x01(\rH\x06\x88\x01\x01\"-\n\x11ListinvoicesIndex\x12\x0b\n\x07\x43REATED\x10\x00\x12\x0b\n\x07UPDATED\x10\x01\x42\x08\n\x06_labelB\x0c\n\n_invstringB\x0f\n\r_payment_hashB\x0b\n\t_offer_idB\x08\n\x06_indexB\x08\n\x06_startB\x08\n\x06_limit\"C\n\x14ListinvoicesResponse\x12+\n\x08invoices\x18\x01 \x03(\x0b\x32\x19.cln.ListinvoicesInvoices\"\xd4\x06\n\x14ListinvoicesInvoices\x12\r\n\x05label\x18\x01 \x01(\t\x12\x18\n\x0b\x64\x65scription\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12\x44\n\x06status\x18\x04 \x01(\x0e\x32\x34.cln.ListinvoicesInvoices.ListinvoicesInvoicesStatus\x12\x12\n\nexpires_at\x18\x05 \x01(\x04\x12%\n\x0b\x61mount_msat\x18\x06 \x01(\x0b\x32\x0b.cln.AmountH\x01\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x07 \x01(\tH\x02\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x08 \x01(\tH\x03\x88\x01\x01\x12\x1b\n\x0elocal_offer_id\x18\t \x01(\x0cH\x04\x88\x01\x01\x12\x1e\n\x11invreq_payer_note\x18\x0f \x01(\tH\x05\x88\x01\x01\x12\x1a\n\rcreated_index\x18\x10 \x01(\x04H\x06\x88\x01\x01\x12\x1a\n\rupdated_index\x18\x11 \x01(\x04H\x07\x88\x01\x01\x12\x16\n\tpay_index\x18\x0b \x01(\x04H\x08\x88\x01\x01\x12.\n\x14\x61mount_received_msat\x18\x0c \x01(\x0b\x32\x0b.cln.AmountH\t\x88\x01\x01\x12\x14\n\x07paid_at\x18\r \x01(\x04H\n\x88\x01\x01\x12\x42\n\rpaid_outpoint\x18\x12 \x01(\x0b\x32&.cln.ListinvoicesInvoicesPaid_outpointH\x0b\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\x0e \x01(\x0cH\x0c\x88\x01\x01\"?\n\x1aListinvoicesInvoicesStatus\x12\n\n\x06UNPAID\x10\x00\x12\x08\n\x04PAID\x10\x01\x12\x0b\n\x07\x45XPIRED\x10\x02\x42\x0e\n\x0c_descriptionB\x0e\n\x0c_amount_msatB\t\n\x07_bolt11B\t\n\x07_bolt12B\x11\n\x0f_local_offer_idB\x14\n\x12_invreq_payer_noteB\x10\n\x0e_created_indexB\x10\n\x0e_updated_indexB\x0c\n\n_pay_indexB\x17\n\x15_amount_received_msatB\n\n\x08_paid_atB\x10\n\x0e_paid_outpointB\x13\n\x11_payment_preimage\"_\n!ListinvoicesInvoicesPaid_outpoint\x12\x11\n\x04txid\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x12\x13\n\x06outnum\x18\x02 \x01(\rH\x01\x88\x01\x01\x42\x07\n\x05_txidB\t\n\x07_outnum\"\x8a\x03\n\x10SendonionRequest\x12\r\n\x05onion\x18\x01 \x01(\x0c\x12*\n\tfirst_hop\x18\x02 \x01(\x0b\x32\x17.cln.SendonionFirst_hop\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12\x12\n\x05label\x18\x04 \x01(\tH\x00\x88\x01\x01\x12\x16\n\x0eshared_secrets\x18\x05 \x03(\x0c\x12\x13\n\x06partid\x18\x06 \x01(\rH\x01\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x07 \x01(\tH\x02\x88\x01\x01\x12%\n\x0b\x61mount_msat\x18\x0c \x01(\x0b\x32\x0b.cln.AmountH\x03\x88\x01\x01\x12\x18\n\x0b\x64\x65stination\x18\t \x01(\x0cH\x04\x88\x01\x01\x12\x1a\n\rlocalinvreqid\x18\r \x01(\x0cH\x05\x88\x01\x01\x12\x14\n\x07groupid\x18\x0b \x01(\x04H\x06\x88\x01\x01\x42\x08\n\x06_labelB\t\n\x07_partidB\t\n\x07_bolt11B\x0e\n\x0c_amount_msatB\x0e\n\x0c_destinationB\x10\n\x0e_localinvreqidB\n\n\x08_groupid\"\xe7\x04\n\x11SendonionResponse\x12\x1a\n\rcreated_index\x18\x0e \x01(\x04H\x00\x88\x01\x01\x12\n\n\x02id\x18\x01 \x01(\x04\x12\x14\n\x0cpayment_hash\x18\x02 \x01(\x0c\x12\x36\n\x06status\x18\x03 \x01(\x0e\x32&.cln.SendonionResponse.SendonionStatus\x12%\n\x0b\x61mount_msat\x18\x04 \x01(\x0b\x32\x0b.cln.AmountH\x01\x88\x01\x01\x12\x18\n\x0b\x64\x65stination\x18\x05 \x01(\x0cH\x02\x88\x01\x01\x12\x12\n\ncreated_at\x18\x06 \x01(\x04\x12%\n\x10\x61mount_sent_msat\x18\x07 \x01(\x0b\x32\x0b.cln.Amount\x12\x12\n\x05label\x18\x08 \x01(\tH\x03\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\t \x01(\tH\x04\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\n \x01(\tH\x05\x88\x01\x01\x12\x13\n\x06partid\x18\r \x01(\x04H\x06\x88\x01\x01\x12\x1a\n\rupdated_index\x18\x0f \x01(\x04H\x07\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\x0b \x01(\x0cH\x08\x88\x01\x01\x12\x14\n\x07message\x18\x0c \x01(\tH\t\x88\x01\x01\",\n\x0fSendonionStatus\x12\x0b\n\x07PENDING\x10\x00\x12\x0c\n\x08\x43OMPLETE\x10\x01\x42\x10\n\x0e_created_indexB\x0e\n\x0c_amount_msatB\x0e\n\x0c_destinationB\x08\n\x06_labelB\t\n\x07_bolt11B\t\n\x07_bolt12B\t\n\x07_partidB\x10\n\x0e_updated_indexB\x13\n\x11_payment_preimageB\n\n\x08_message\"Q\n\x12SendonionFirst_hop\x12\n\n\x02id\x18\x01 \x01(\x0c\x12 \n\x0b\x61mount_msat\x18\x02 \x01(\x0b\x32\x0b.cln.Amount\x12\r\n\x05\x64\x65lay\x18\x03 \x01(\r\"\xa0\x03\n\x13ListsendpaysRequest\x12\x13\n\x06\x62olt11\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x19\n\x0cpayment_hash\x18\x02 \x01(\x0cH\x01\x88\x01\x01\x12@\n\x06status\x18\x03 \x01(\x0e\x32+.cln.ListsendpaysRequest.ListsendpaysStatusH\x02\x88\x01\x01\x12>\n\x05index\x18\x04 \x01(\x0e\x32*.cln.ListsendpaysRequest.ListsendpaysIndexH\x03\x88\x01\x01\x12\x12\n\x05start\x18\x05 \x01(\x04H\x04\x88\x01\x01\x12\x12\n\x05limit\x18\x06 \x01(\rH\x05\x88\x01\x01\";\n\x12ListsendpaysStatus\x12\x0b\n\x07PENDING\x10\x00\x12\x0c\n\x08\x43OMPLETE\x10\x01\x12\n\n\x06\x46\x41ILED\x10\x02\"-\n\x11ListsendpaysIndex\x12\x0b\n\x07\x43REATED\x10\x00\x12\x0b\n\x07UPDATED\x10\x01\x42\t\n\x07_bolt11B\x0f\n\r_payment_hashB\t\n\x07_statusB\x08\n\x06_indexB\x08\n\x06_startB\x08\n\x06_limit\"C\n\x14ListsendpaysResponse\x12+\n\x08payments\x18\x01 \x03(\x0b\x32\x19.cln.ListsendpaysPayments\"\xd0\x05\n\x14ListsendpaysPayments\x12\x1a\n\rcreated_index\x18\x10 \x01(\x04H\x00\x88\x01\x01\x12\n\n\x02id\x18\x01 \x01(\x04\x12\x0f\n\x07groupid\x18\x02 \x01(\x04\x12\x13\n\x06partid\x18\x0f \x01(\x04H\x01\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12\x1a\n\rupdated_index\x18\x11 \x01(\x04H\x02\x88\x01\x01\x12\x44\n\x06status\x18\x04 \x01(\x0e\x32\x34.cln.ListsendpaysPayments.ListsendpaysPaymentsStatus\x12%\n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x03\x88\x01\x01\x12\x18\n\x0b\x64\x65stination\x18\x06 \x01(\x0cH\x04\x88\x01\x01\x12\x12\n\ncreated_at\x18\x07 \x01(\x04\x12%\n\x10\x61mount_sent_msat\x18\x08 \x01(\x0b\x32\x0b.cln.Amount\x12\x12\n\x05label\x18\t \x01(\tH\x05\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\n \x01(\tH\x06\x88\x01\x01\x12\x18\n\x0b\x64\x65scription\x18\x0e \x01(\tH\x07\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x0b \x01(\tH\x08\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\x0c \x01(\x0cH\t\x88\x01\x01\x12\x17\n\nerroronion\x18\r \x01(\x0cH\n\x88\x01\x01\"C\n\x1aListsendpaysPaymentsStatus\x12\x0b\n\x07PENDING\x10\x00\x12\n\n\x06\x46\x41ILED\x10\x01\x12\x0c\n\x08\x43OMPLETE\x10\x02\x42\x10\n\x0e_created_indexB\t\n\x07_partidB\x10\n\x0e_updated_indexB\x0e\n\x0c_amount_msatB\x0e\n\x0c_destinationB\x08\n\x06_labelB\t\n\x07_bolt11B\x0e\n\x0c_descriptionB\t\n\x07_bolt12B\x13\n\x11_payment_preimageB\r\n\x0b_erroronion\"\x19\n\x17ListtransactionsRequest\"S\n\x18ListtransactionsResponse\x12\x37\n\x0ctransactions\x18\x01 \x03(\x0b\x32!.cln.ListtransactionsTransactions\"\xf8\x01\n\x1cListtransactionsTransactions\x12\x0c\n\x04hash\x18\x01 \x01(\x0c\x12\r\n\x05rawtx\x18\x02 \x01(\x0c\x12\x13\n\x0b\x62lockheight\x18\x03 \x01(\r\x12\x0f\n\x07txindex\x18\x04 \x01(\r\x12\x10\n\x08locktime\x18\x07 \x01(\r\x12\x0f\n\x07version\x18\x08 \x01(\r\x12\x37\n\x06inputs\x18\t \x03(\x0b\x32\'.cln.ListtransactionsTransactionsInputs\x12\x39\n\x07outputs\x18\n \x03(\x0b\x32(.cln.ListtransactionsTransactionsOutputs\"S\n\"ListtransactionsTransactionsInputs\x12\x0c\n\x04txid\x18\x01 \x01(\x0c\x12\r\n\x05index\x18\x02 \x01(\r\x12\x10\n\x08sequence\x18\x03 \x01(\r\"l\n#ListtransactionsTransactionsOutputs\x12\r\n\x05index\x18\x01 \x01(\r\x12 \n\x0b\x61mount_msat\x18\x06 \x01(\x0b\x32\x0b.cln.Amount\x12\x14\n\x0cscriptPubKey\x18\x03 \x01(\x0c\"\xda\x03\n\nPayRequest\x12\x0e\n\x06\x62olt11\x18\x01 \x01(\t\x12%\n\x0b\x61mount_msat\x18\r \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12\x12\n\x05label\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x17\n\nriskfactor\x18\x08 \x01(\x01H\x02\x88\x01\x01\x12\x1a\n\rmaxfeepercent\x18\x04 \x01(\x01H\x03\x88\x01\x01\x12\x16\n\tretry_for\x18\x05 \x01(\rH\x04\x88\x01\x01\x12\x15\n\x08maxdelay\x18\x06 \x01(\rH\x05\x88\x01\x01\x12#\n\texemptfee\x18\x07 \x01(\x0b\x32\x0b.cln.AmountH\x06\x88\x01\x01\x12\x1a\n\rlocalinvreqid\x18\x0e \x01(\x0cH\x07\x88\x01\x01\x12\x0f\n\x07\x65xclude\x18\n \x03(\t\x12 \n\x06maxfee\x18\x0b \x01(\x0b\x32\x0b.cln.AmountH\x08\x88\x01\x01\x12\x18\n\x0b\x64\x65scription\x18\x0c \x01(\tH\t\x88\x01\x01\x42\x0e\n\x0c_amount_msatB\x08\n\x06_labelB\r\n\x0b_riskfactorB\x10\n\x0e_maxfeepercentB\x0c\n\n_retry_forB\x0b\n\t_maxdelayB\x0c\n\n_exemptfeeB\x10\n\x0e_localinvreqidB\t\n\x07_maxfeeB\x0e\n\x0c_description\"\xfb\x02\n\x0bPayResponse\x12\x18\n\x10payment_preimage\x18\x01 \x01(\x0c\x12\x18\n\x0b\x64\x65stination\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12\x12\n\ncreated_at\x18\x04 \x01(\x01\x12\r\n\x05parts\x18\x05 \x01(\r\x12 \n\x0b\x61mount_msat\x18\x06 \x01(\x0b\x32\x0b.cln.Amount\x12%\n\x10\x61mount_sent_msat\x18\x07 \x01(\x0b\x32\x0b.cln.Amount\x12\'\n\x1awarning_partial_completion\x18\x08 \x01(\tH\x01\x88\x01\x01\x12*\n\x06status\x18\t \x01(\x0e\x32\x1a.cln.PayResponse.PayStatus\"2\n\tPayStatus\x12\x0c\n\x08\x43OMPLETE\x10\x00\x12\x0b\n\x07PENDING\x10\x01\x12\n\n\x06\x46\x41ILED\x10\x02\x42\x0e\n\x0c_destinationB\x1d\n\x1b_warning_partial_completion\"*\n\x10ListnodesRequest\x12\x0f\n\x02id\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x42\x05\n\x03_id\"7\n\x11ListnodesResponse\x12\"\n\x05nodes\x18\x01 \x03(\x0b\x32\x13.cln.ListnodesNodes\"\xe1\x01\n\x0eListnodesNodes\x12\x0e\n\x06nodeid\x18\x01 \x01(\x0c\x12\x1b\n\x0elast_timestamp\x18\x02 \x01(\rH\x00\x88\x01\x01\x12\x12\n\x05\x61lias\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x12\n\x05\x63olor\x18\x04 \x01(\x0cH\x02\x88\x01\x01\x12\x15\n\x08\x66\x65\x61tures\x18\x05 \x01(\x0cH\x03\x88\x01\x01\x12/\n\taddresses\x18\x06 \x03(\x0b\x32\x1c.cln.ListnodesNodesAddressesB\x11\n\x0f_last_timestampB\x08\n\x06_aliasB\x08\n\x06_colorB\x0b\n\t_features\"\xe8\x01\n\x17ListnodesNodesAddresses\x12K\n\titem_type\x18\x01 \x01(\x0e\x32\x38.cln.ListnodesNodesAddresses.ListnodesNodesAddressesType\x12\x0c\n\x04port\x18\x02 \x01(\r\x12\x14\n\x07\x61\x64\x64ress\x18\x03 \x01(\tH\x00\x88\x01\x01\"P\n\x1bListnodesNodesAddressesType\x12\x07\n\x03\x44NS\x10\x00\x12\x08\n\x04IPV4\x10\x01\x12\x08\n\x04IPV6\x10\x02\x12\t\n\x05TORV2\x10\x03\x12\t\n\x05TORV3\x10\x04\x42\n\n\x08_address\"g\n\x15WaitanyinvoiceRequest\x12\x1a\n\rlastpay_index\x18\x01 \x01(\x04H\x00\x88\x01\x01\x12\x14\n\x07timeout\x18\x02 \x01(\x04H\x01\x88\x01\x01\x42\x10\n\x0e_lastpay_indexB\n\n\x08_timeout\"\xbf\x05\n\x16WaitanyinvoiceResponse\x12\r\n\x05label\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12@\n\x06status\x18\x04 \x01(\x0e\x32\x30.cln.WaitanyinvoiceResponse.WaitanyinvoiceStatus\x12\x12\n\nexpires_at\x18\x05 \x01(\x04\x12%\n\x0b\x61mount_msat\x18\x06 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x07 \x01(\tH\x01\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x08 \x01(\tH\x02\x88\x01\x01\x12\x1a\n\rcreated_index\x18\r \x01(\x04H\x03\x88\x01\x01\x12\x1a\n\rupdated_index\x18\x0e \x01(\x04H\x04\x88\x01\x01\x12\x16\n\tpay_index\x18\t \x01(\x04H\x05\x88\x01\x01\x12.\n\x14\x61mount_received_msat\x18\n \x01(\x0b\x32\x0b.cln.AmountH\x06\x88\x01\x01\x12\x14\n\x07paid_at\x18\x0b \x01(\x04H\x07\x88\x01\x01\x12<\n\rpaid_outpoint\x18\x0f \x01(\x0b\x32 .cln.WaitanyinvoicePaid_outpointH\x08\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\x0c \x01(\x0cH\t\x88\x01\x01\"-\n\x14WaitanyinvoiceStatus\x12\x08\n\x04PAID\x10\x00\x12\x0b\n\x07\x45XPIRED\x10\x01\x42\x0e\n\x0c_amount_msatB\t\n\x07_bolt11B\t\n\x07_bolt12B\x10\n\x0e_created_indexB\x10\n\x0e_updated_indexB\x0c\n\n_pay_indexB\x17\n\x15_amount_received_msatB\n\n\x08_paid_atB\x10\n\x0e_paid_outpointB\x13\n\x11_payment_preimage\"Y\n\x1bWaitanyinvoicePaid_outpoint\x12\x11\n\x04txid\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x12\x13\n\x06outnum\x18\x02 \x01(\rH\x01\x88\x01\x01\x42\x07\n\x05_txidB\t\n\x07_outnum\"#\n\x12WaitinvoiceRequest\x12\r\n\x05label\x18\x01 \x01(\t\"\xb0\x05\n\x13WaitinvoiceResponse\x12\r\n\x05label\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12:\n\x06status\x18\x04 \x01(\x0e\x32*.cln.WaitinvoiceResponse.WaitinvoiceStatus\x12\x12\n\nexpires_at\x18\x05 \x01(\x04\x12%\n\x0b\x61mount_msat\x18\x06 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x07 \x01(\tH\x01\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x08 \x01(\tH\x02\x88\x01\x01\x12\x1a\n\rcreated_index\x18\r \x01(\x04H\x03\x88\x01\x01\x12\x1a\n\rupdated_index\x18\x0e \x01(\x04H\x04\x88\x01\x01\x12\x16\n\tpay_index\x18\t \x01(\x04H\x05\x88\x01\x01\x12.\n\x14\x61mount_received_msat\x18\n \x01(\x0b\x32\x0b.cln.AmountH\x06\x88\x01\x01\x12\x14\n\x07paid_at\x18\x0b \x01(\x04H\x07\x88\x01\x01\x12\x39\n\rpaid_outpoint\x18\x0f \x01(\x0b\x32\x1d.cln.WaitinvoicePaid_outpointH\x08\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\x0c \x01(\x0cH\t\x88\x01\x01\"*\n\x11WaitinvoiceStatus\x12\x08\n\x04PAID\x10\x00\x12\x0b\n\x07\x45XPIRED\x10\x01\x42\x0e\n\x0c_amount_msatB\t\n\x07_bolt11B\t\n\x07_bolt12B\x10\n\x0e_created_indexB\x10\n\x0e_updated_indexB\x0c\n\n_pay_indexB\x17\n\x15_amount_received_msatB\n\n\x08_paid_atB\x10\n\x0e_paid_outpointB\x13\n\x11_payment_preimage\"V\n\x18WaitinvoicePaid_outpoint\x12\x11\n\x04txid\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x12\x13\n\x06outnum\x18\x02 \x01(\rH\x01\x88\x01\x01\x42\x07\n\x05_txidB\t\n\x07_outnum\"\x8e\x01\n\x12WaitsendpayRequest\x12\x14\n\x0cpayment_hash\x18\x01 \x01(\x0c\x12\x14\n\x07timeout\x18\x03 \x01(\rH\x00\x88\x01\x01\x12\x13\n\x06partid\x18\x02 \x01(\x04H\x01\x88\x01\x01\x12\x14\n\x07groupid\x18\x04 \x01(\x04H\x02\x88\x01\x01\x42\n\n\x08_timeoutB\t\n\x07_partidB\n\n\x08_groupid\"\x8e\x05\n\x13WaitsendpayResponse\x12\x1a\n\rcreated_index\x18\x0f \x01(\x04H\x00\x88\x01\x01\x12\n\n\x02id\x18\x01 \x01(\x04\x12\x14\n\x07groupid\x18\x02 \x01(\x04H\x01\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12:\n\x06status\x18\x04 \x01(\x0e\x32*.cln.WaitsendpayResponse.WaitsendpayStatus\x12%\n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x02\x88\x01\x01\x12\x18\n\x0b\x64\x65stination\x18\x06 \x01(\x0cH\x03\x88\x01\x01\x12\x12\n\ncreated_at\x18\x07 \x01(\x04\x12\x1a\n\rupdated_index\x18\x10 \x01(\x04H\x04\x88\x01\x01\x12\x19\n\x0c\x63ompleted_at\x18\x0e \x01(\x01H\x05\x88\x01\x01\x12%\n\x10\x61mount_sent_msat\x18\x08 \x01(\x0b\x32\x0b.cln.Amount\x12\x12\n\x05label\x18\t \x01(\tH\x06\x88\x01\x01\x12\x13\n\x06partid\x18\n \x01(\x04H\x07\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x0b \x01(\tH\x08\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x0c \x01(\tH\t\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\r \x01(\x0cH\n\x88\x01\x01\"!\n\x11WaitsendpayStatus\x12\x0c\n\x08\x43OMPLETE\x10\x00\x42\x10\n\x0e_created_indexB\n\n\x08_groupidB\x0e\n\x0c_amount_msatB\x0e\n\x0c_destinationB\x10\n\x0e_updated_indexB\x0f\n\r_completed_atB\x08\n\x06_labelB\t\n\x07_partidB\t\n\x07_bolt11B\t\n\x07_bolt12B\x13\n\x11_payment_preimage\"\x97\x01\n\x0eNewaddrRequest\x12@\n\x0b\x61\x64\x64resstype\x18\x01 \x01(\x0e\x32&.cln.NewaddrRequest.NewaddrAddresstypeH\x00\x88\x01\x01\"3\n\x12NewaddrAddresstype\x12\n\n\x06\x42\x45\x43H32\x10\x00\x12\x08\n\x04P2TR\x10\x03\x12\x07\n\x03\x41LL\x10\x02\x42\x0e\n\x0c_addresstype\"M\n\x0fNewaddrResponse\x12\x11\n\x04p2tr\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06\x62\x65\x63h32\x18\x01 \x01(\tH\x01\x88\x01\x01\x42\x07\n\x05_p2trB\t\n\x07_bech32\"\xca\x01\n\x0fWithdrawRequest\x12\x13\n\x0b\x64\x65stination\x18\x01 \x01(\t\x12&\n\x07satoshi\x18\x02 \x01(\x0b\x32\x10.cln.AmountOrAllH\x00\x88\x01\x01\x12\"\n\x07\x66\x65\x65rate\x18\x05 \x01(\x0b\x32\x0c.cln.FeerateH\x01\x88\x01\x01\x12\x14\n\x07minconf\x18\x03 \x01(\rH\x02\x88\x01\x01\x12\x1c\n\x05utxos\x18\x04 \x03(\x0b\x32\r.cln.OutpointB\n\n\x08_satoshiB\n\n\x08_feerateB\n\n\x08_minconf\":\n\x10WithdrawResponse\x12\n\n\x02tx\x18\x01 \x01(\x0c\x12\x0c\n\x04txid\x18\x02 \x01(\x0c\x12\x0c\n\x04psbt\x18\x03 \x01(\t\"\x82\x03\n\x0eKeysendRequest\x12\x13\n\x0b\x64\x65stination\x18\x01 \x01(\x0c\x12 \n\x0b\x61mount_msat\x18\n \x01(\x0b\x32\x0b.cln.Amount\x12\x12\n\x05label\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x1a\n\rmaxfeepercent\x18\x04 \x01(\x01H\x01\x88\x01\x01\x12\x16\n\tretry_for\x18\x05 \x01(\rH\x02\x88\x01\x01\x12\x15\n\x08maxdelay\x18\x06 \x01(\rH\x03\x88\x01\x01\x12#\n\texemptfee\x18\x07 \x01(\x0b\x32\x0b.cln.AmountH\x04\x88\x01\x01\x12+\n\nroutehints\x18\x08 \x01(\x0b\x32\x12.cln.RoutehintListH\x05\x88\x01\x01\x12&\n\textratlvs\x18\t \x01(\x0b\x32\x0e.cln.TlvStreamH\x06\x88\x01\x01\x42\x08\n\x06_labelB\x10\n\x0e_maxfeepercentB\x0c\n\n_retry_forB\x0b\n\t_maxdelayB\x0c\n\n_exemptfeeB\r\n\x0b_routehintsB\x0c\n\n_extratlvs\"\xf2\x02\n\x0fKeysendResponse\x12\x18\n\x10payment_preimage\x18\x01 \x01(\x0c\x12\x18\n\x0b\x64\x65stination\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12\x12\n\ncreated_at\x18\x04 \x01(\x01\x12\r\n\x05parts\x18\x05 \x01(\r\x12 \n\x0b\x61mount_msat\x18\x06 \x01(\x0b\x32\x0b.cln.Amount\x12%\n\x10\x61mount_sent_msat\x18\x07 \x01(\x0b\x32\x0b.cln.Amount\x12\'\n\x1awarning_partial_completion\x18\x08 \x01(\tH\x01\x88\x01\x01\x12\x32\n\x06status\x18\t \x01(\x0e\x32\".cln.KeysendResponse.KeysendStatus\"\x1d\n\rKeysendStatus\x12\x0c\n\x08\x43OMPLETE\x10\x00\x42\x0e\n\x0c_destinationB\x1d\n\x1b_warning_partial_completion\"\xa4\x03\n\x0f\x46undpsbtRequest\x12!\n\x07satoshi\x18\x01 \x01(\x0b\x32\x10.cln.AmountOrAll\x12\x1d\n\x07\x66\x65\x65rate\x18\x02 \x01(\x0b\x32\x0c.cln.Feerate\x12\x13\n\x0bstartweight\x18\x03 \x01(\r\x12\x14\n\x07minconf\x18\x04 \x01(\rH\x00\x88\x01\x01\x12\x14\n\x07reserve\x18\x05 \x01(\rH\x01\x88\x01\x01\x12\x15\n\x08locktime\x18\x06 \x01(\rH\x02\x88\x01\x01\x12\x1f\n\x12min_witness_weight\x18\x07 \x01(\rH\x03\x88\x01\x01\x12\x1d\n\x10\x65xcess_as_change\x18\x08 \x01(\x08H\x04\x88\x01\x01\x12\x17\n\nnonwrapped\x18\t \x01(\x08H\x05\x88\x01\x01\x12#\n\x16opening_anchor_channel\x18\n \x01(\x08H\x06\x88\x01\x01\x42\n\n\x08_minconfB\n\n\x08_reserveB\x0b\n\t_locktimeB\x15\n\x13_min_witness_weightB\x13\n\x11_excess_as_changeB\r\n\x0b_nonwrappedB\x19\n\x17_opening_anchor_channel\"\xd9\x01\n\x10\x46undpsbtResponse\x12\x0c\n\x04psbt\x18\x01 \x01(\t\x12\x16\n\x0e\x66\x65\x65rate_per_kw\x18\x02 \x01(\r\x12\x1e\n\x16\x65stimated_final_weight\x18\x03 \x01(\r\x12 \n\x0b\x65xcess_msat\x18\x04 \x01(\x0b\x32\x0b.cln.Amount\x12\x1a\n\rchange_outnum\x18\x05 \x01(\rH\x00\x88\x01\x01\x12/\n\x0creservations\x18\x06 \x03(\x0b\x32\x19.cln.FundpsbtReservationsB\x10\n\x0e_change_outnum\"u\n\x14\x46undpsbtReservations\x12\x0c\n\x04txid\x18\x01 \x01(\x0c\x12\x0c\n\x04vout\x18\x02 \x01(\r\x12\x14\n\x0cwas_reserved\x18\x03 \x01(\x08\x12\x10\n\x08reserved\x18\x04 \x01(\x08\x12\x19\n\x11reserved_to_block\x18\x05 \x01(\r\"A\n\x0fSendpsbtRequest\x12\x0c\n\x04psbt\x18\x01 \x01(\t\x12\x14\n\x07reserve\x18\x02 \x01(\x08H\x00\x88\x01\x01\x42\n\n\x08_reserve\",\n\x10SendpsbtResponse\x12\n\n\x02tx\x18\x01 \x01(\x0c\x12\x0c\n\x04txid\x18\x02 \x01(\x0c\"1\n\x0fSignpsbtRequest\x12\x0c\n\x04psbt\x18\x01 \x01(\t\x12\x10\n\x08signonly\x18\x02 \x03(\r\"\'\n\x10SignpsbtResponse\x12\x13\n\x0bsigned_psbt\x18\x01 \x01(\t\"\x9b\x03\n\x0fUtxopsbtRequest\x12\x1c\n\x07satoshi\x18\x01 \x01(\x0b\x32\x0b.cln.Amount\x12\x1d\n\x07\x66\x65\x65rate\x18\x02 \x01(\x0b\x32\x0c.cln.Feerate\x12\x13\n\x0bstartweight\x18\x03 \x01(\r\x12\x1c\n\x05utxos\x18\x04 \x03(\x0b\x32\r.cln.Outpoint\x12\x14\n\x07reserve\x18\x05 \x01(\rH\x00\x88\x01\x01\x12\x17\n\nreservedok\x18\x08 \x01(\x08H\x01\x88\x01\x01\x12\x15\n\x08locktime\x18\x06 \x01(\rH\x02\x88\x01\x01\x12\x1f\n\x12min_witness_weight\x18\x07 \x01(\rH\x03\x88\x01\x01\x12\x1d\n\x10\x65xcess_as_change\x18\t \x01(\x08H\x04\x88\x01\x01\x12#\n\x16opening_anchor_channel\x18\n \x01(\x08H\x05\x88\x01\x01\x42\n\n\x08_reserveB\r\n\x0b_reservedokB\x0b\n\t_locktimeB\x15\n\x13_min_witness_weightB\x13\n\x11_excess_as_changeB\x19\n\x17_opening_anchor_channel\"\xd9\x01\n\x10UtxopsbtResponse\x12\x0c\n\x04psbt\x18\x01 \x01(\t\x12\x16\n\x0e\x66\x65\x65rate_per_kw\x18\x02 \x01(\r\x12\x1e\n\x16\x65stimated_final_weight\x18\x03 \x01(\r\x12 \n\x0b\x65xcess_msat\x18\x04 \x01(\x0b\x32\x0b.cln.Amount\x12\x1a\n\rchange_outnum\x18\x05 \x01(\rH\x00\x88\x01\x01\x12/\n\x0creservations\x18\x06 \x03(\x0b\x32\x19.cln.UtxopsbtReservationsB\x10\n\x0e_change_outnum\"u\n\x14UtxopsbtReservations\x12\x0c\n\x04txid\x18\x01 \x01(\x0c\x12\x0c\n\x04vout\x18\x02 \x01(\r\x12\x14\n\x0cwas_reserved\x18\x03 \x01(\x08\x12\x10\n\x08reserved\x18\x04 \x01(\x08\x12\x19\n\x11reserved_to_block\x18\x05 \x01(\r\" \n\x10TxdiscardRequest\x12\x0c\n\x04txid\x18\x01 \x01(\x0c\"6\n\x11TxdiscardResponse\x12\x13\n\x0bunsigned_tx\x18\x01 \x01(\x0c\x12\x0c\n\x04txid\x18\x02 \x01(\x0c\"\xa4\x01\n\x10TxprepareRequest\x12 \n\x07outputs\x18\x05 \x03(\x0b\x32\x0f.cln.OutputDesc\x12\"\n\x07\x66\x65\x65rate\x18\x02 \x01(\x0b\x32\x0c.cln.FeerateH\x00\x88\x01\x01\x12\x14\n\x07minconf\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\x1c\n\x05utxos\x18\x04 \x03(\x0b\x32\r.cln.OutpointB\n\n\x08_feerateB\n\n\x08_minconf\"D\n\x11TxprepareResponse\x12\x0c\n\x04psbt\x18\x01 \x01(\t\x12\x13\n\x0bunsigned_tx\x18\x02 \x01(\x0c\x12\x0c\n\x04txid\x18\x03 \x01(\x0c\"\x1d\n\rTxsendRequest\x12\x0c\n\x04txid\x18\x01 \x01(\x0c\"8\n\x0eTxsendResponse\x12\x0c\n\x04psbt\x18\x01 \x01(\t\x12\n\n\x02tx\x18\x02 \x01(\x0c\x12\x0c\n\x04txid\x18\x03 \x01(\x0c\"1\n\x17ListpeerchannelsRequest\x12\x0f\n\x02id\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x42\x05\n\x03_id\"K\n\x18ListpeerchannelsResponse\x12/\n\x08\x63hannels\x18\x01 \x03(\x0b\x32\x1d.cln.ListpeerchannelsChannels\"\xa2\x1a\n\x18ListpeerchannelsChannels\x12\x14\n\x07peer_id\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x12\x1b\n\x0epeer_connected\x18\x02 \x01(\x08H\x01\x88\x01\x01\x12O\n\x05state\x18\x03 \x01(\x0e\x32;.cln.ListpeerchannelsChannels.ListpeerchannelsChannelsStateH\x02\x88\x01\x01\x12\x19\n\x0cscratch_txid\x18\x04 \x01(\x0cH\x03\x88\x01\x01\x12:\n\x07updates\x18\x37 \x01(\x0b\x32$.cln.ListpeerchannelsChannelsUpdatesH\x04\x88\x01\x01\x12\x1e\n\x11ignore_fee_limits\x18\x36 \x01(\x08H\x05\x88\x01\x01\x12:\n\x07\x66\x65\x65rate\x18\x06 \x01(\x0b\x32$.cln.ListpeerchannelsChannelsFeerateH\x06\x88\x01\x01\x12\x12\n\x05owner\x18\x07 \x01(\tH\x07\x88\x01\x01\x12\x1d\n\x10short_channel_id\x18\x08 \x01(\tH\x08\x88\x01\x01\x12\x17\n\nchannel_id\x18\t \x01(\x0cH\t\x88\x01\x01\x12\x19\n\x0c\x66unding_txid\x18\n \x01(\x0cH\n\x88\x01\x01\x12\x1b\n\x0e\x66unding_outnum\x18\x0b \x01(\rH\x0b\x88\x01\x01\x12\x1c\n\x0finitial_feerate\x18\x0c \x01(\tH\x0c\x88\x01\x01\x12\x19\n\x0clast_feerate\x18\r \x01(\tH\r\x88\x01\x01\x12\x19\n\x0cnext_feerate\x18\x0e \x01(\tH\x0e\x88\x01\x01\x12\x1a\n\rnext_fee_step\x18\x0f \x01(\rH\x0f\x88\x01\x01\x12\x37\n\x08inflight\x18\x10 \x03(\x0b\x32%.cln.ListpeerchannelsChannelsInflight\x12\x15\n\x08\x63lose_to\x18\x11 \x01(\x0cH\x10\x88\x01\x01\x12\x14\n\x07private\x18\x12 \x01(\x08H\x11\x88\x01\x01\x12%\n\x06opener\x18\x13 \x01(\x0e\x32\x10.cln.ChannelSideH\x12\x88\x01\x01\x12%\n\x06\x63loser\x18\x14 \x01(\x0e\x32\x10.cln.ChannelSideH\x13\x88\x01\x01\x12:\n\x07\x66unding\x18\x16 \x01(\x0b\x32$.cln.ListpeerchannelsChannelsFundingH\x14\x88\x01\x01\x12$\n\nto_us_msat\x18\x17 \x01(\x0b\x32\x0b.cln.AmountH\x15\x88\x01\x01\x12(\n\x0emin_to_us_msat\x18\x18 \x01(\x0b\x32\x0b.cln.AmountH\x16\x88\x01\x01\x12(\n\x0emax_to_us_msat\x18\x19 \x01(\x0b\x32\x0b.cln.AmountH\x17\x88\x01\x01\x12$\n\ntotal_msat\x18\x1a \x01(\x0b\x32\x0b.cln.AmountH\x18\x88\x01\x01\x12\'\n\rfee_base_msat\x18\x1b \x01(\x0b\x32\x0b.cln.AmountH\x19\x88\x01\x01\x12(\n\x1b\x66\x65\x65_proportional_millionths\x18\x1c \x01(\rH\x1a\x88\x01\x01\x12)\n\x0f\x64ust_limit_msat\x18\x1d \x01(\x0b\x32\x0b.cln.AmountH\x1b\x88\x01\x01\x12\x30\n\x16max_total_htlc_in_msat\x18\x1e \x01(\x0b\x32\x0b.cln.AmountH\x1c\x88\x01\x01\x12,\n\x12their_reserve_msat\x18\x1f \x01(\x0b\x32\x0b.cln.AmountH\x1d\x88\x01\x01\x12*\n\x10our_reserve_msat\x18 \x01(\x0b\x32\x0b.cln.AmountH\x1e\x88\x01\x01\x12(\n\x0espendable_msat\x18! \x01(\x0b\x32\x0b.cln.AmountH\x1f\x88\x01\x01\x12)\n\x0freceivable_msat\x18\" \x01(\x0b\x32\x0b.cln.AmountH \x88\x01\x01\x12.\n\x14minimum_htlc_in_msat\x18# \x01(\x0b\x32\x0b.cln.AmountH!\x88\x01\x01\x12/\n\x15minimum_htlc_out_msat\x18$ \x01(\x0b\x32\x0b.cln.AmountH\"\x88\x01\x01\x12/\n\x15maximum_htlc_out_msat\x18% \x01(\x0b\x32\x0b.cln.AmountH#\x88\x01\x01\x12 \n\x13their_to_self_delay\x18& \x01(\rH$\x88\x01\x01\x12\x1e\n\x11our_to_self_delay\x18\' \x01(\rH%\x88\x01\x01\x12\x1f\n\x12max_accepted_htlcs\x18( \x01(\rH&\x88\x01\x01\x12\x36\n\x05\x61lias\x18) \x01(\x0b\x32\".cln.ListpeerchannelsChannelsAliasH\'\x88\x01\x01\x12\x0e\n\x06status\x18+ \x03(\t\x12 \n\x13in_payments_offered\x18, \x01(\x04H(\x88\x01\x01\x12)\n\x0fin_offered_msat\x18- \x01(\x0b\x32\x0b.cln.AmountH)\x88\x01\x01\x12\"\n\x15in_payments_fulfilled\x18. \x01(\x04H*\x88\x01\x01\x12+\n\x11in_fulfilled_msat\x18/ \x01(\x0b\x32\x0b.cln.AmountH+\x88\x01\x01\x12!\n\x14out_payments_offered\x18\x30 \x01(\x04H,\x88\x01\x01\x12*\n\x10out_offered_msat\x18\x31 \x01(\x0b\x32\x0b.cln.AmountH-\x88\x01\x01\x12#\n\x16out_payments_fulfilled\x18\x32 \x01(\x04H.\x88\x01\x01\x12,\n\x12out_fulfilled_msat\x18\x33 \x01(\x0b\x32\x0b.cln.AmountH/\x88\x01\x01\x12\x31\n\x05htlcs\x18\x34 \x03(\x0b\x32\".cln.ListpeerchannelsChannelsHtlcs\x12\x1a\n\rclose_to_addr\x18\x35 \x01(\tH0\x88\x01\x01\"\x80\x03\n\x1dListpeerchannelsChannelsState\x12\x0c\n\x08OPENINGD\x10\x00\x12\x1c\n\x18\x43HANNELD_AWAITING_LOCKIN\x10\x01\x12\x13\n\x0f\x43HANNELD_NORMAL\x10\x02\x12\x1a\n\x16\x43HANNELD_SHUTTING_DOWN\x10\x03\x12\x18\n\x14\x43LOSINGD_SIGEXCHANGE\x10\x04\x12\x15\n\x11\x43LOSINGD_COMPLETE\x10\x05\x12\x17\n\x13\x41WAITING_UNILATERAL\x10\x06\x12\x16\n\x12\x46UNDING_SPEND_SEEN\x10\x07\x12\x0b\n\x07ONCHAIN\x10\x08\x12\x17\n\x13\x44UALOPEND_OPEN_INIT\x10\t\x12\x1d\n\x19\x44UALOPEND_AWAITING_LOCKIN\x10\n\x12\x1c\n\x18\x43HANNELD_AWAITING_SPLICE\x10\x0b\x12\x1c\n\x18\x44UALOPEND_OPEN_COMMITTED\x10\x0c\x12\x1f\n\x1b\x44UALOPEND_OPEN_COMMIT_READY\x10\rB\n\n\x08_peer_idB\x11\n\x0f_peer_connectedB\x08\n\x06_stateB\x0f\n\r_scratch_txidB\n\n\x08_updatesB\x14\n\x12_ignore_fee_limitsB\n\n\x08_feerateB\x08\n\x06_ownerB\x13\n\x11_short_channel_idB\r\n\x0b_channel_idB\x0f\n\r_funding_txidB\x11\n\x0f_funding_outnumB\x12\n\x10_initial_feerateB\x0f\n\r_last_feerateB\x0f\n\r_next_feerateB\x10\n\x0e_next_fee_stepB\x0b\n\t_close_toB\n\n\x08_privateB\t\n\x07_openerB\t\n\x07_closerB\n\n\x08_fundingB\r\n\x0b_to_us_msatB\x11\n\x0f_min_to_us_msatB\x11\n\x0f_max_to_us_msatB\r\n\x0b_total_msatB\x10\n\x0e_fee_base_msatB\x1e\n\x1c_fee_proportional_millionthsB\x12\n\x10_dust_limit_msatB\x19\n\x17_max_total_htlc_in_msatB\x15\n\x13_their_reserve_msatB\x13\n\x11_our_reserve_msatB\x11\n\x0f_spendable_msatB\x12\n\x10_receivable_msatB\x17\n\x15_minimum_htlc_in_msatB\x18\n\x16_minimum_htlc_out_msatB\x18\n\x16_maximum_htlc_out_msatB\x16\n\x14_their_to_self_delayB\x14\n\x12_our_to_self_delayB\x15\n\x13_max_accepted_htlcsB\x08\n\x06_aliasB\x16\n\x14_in_payments_offeredB\x12\n\x10_in_offered_msatB\x18\n\x16_in_payments_fulfilledB\x14\n\x12_in_fulfilled_msatB\x17\n\x15_out_payments_offeredB\x13\n\x11_out_offered_msatB\x19\n\x17_out_payments_fulfilledB\x15\n\x13_out_fulfilled_msatB\x10\n\x0e_close_to_addr\"\xb6\x01\n\x1fListpeerchannelsChannelsUpdates\x12=\n\x05local\x18\x01 \x01(\x0b\x32).cln.ListpeerchannelsChannelsUpdatesLocalH\x00\x88\x01\x01\x12?\n\x06remote\x18\x02 \x01(\x0b\x32*.cln.ListpeerchannelsChannelsUpdatesRemoteH\x01\x88\x01\x01\x42\x08\n\x06_localB\t\n\x07_remote\"\xe7\x02\n$ListpeerchannelsChannelsUpdatesLocal\x12+\n\x11htlc_minimum_msat\x18\x01 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12+\n\x11htlc_maximum_msat\x18\x02 \x01(\x0b\x32\x0b.cln.AmountH\x01\x88\x01\x01\x12\x1e\n\x11\x63ltv_expiry_delta\x18\x03 \x01(\rH\x02\x88\x01\x01\x12\'\n\rfee_base_msat\x18\x04 \x01(\x0b\x32\x0b.cln.AmountH\x03\x88\x01\x01\x12(\n\x1b\x66\x65\x65_proportional_millionths\x18\x05 \x01(\rH\x04\x88\x01\x01\x42\x14\n\x12_htlc_minimum_msatB\x14\n\x12_htlc_maximum_msatB\x14\n\x12_cltv_expiry_deltaB\x10\n\x0e_fee_base_msatB\x1e\n\x1c_fee_proportional_millionths\"\xe8\x02\n%ListpeerchannelsChannelsUpdatesRemote\x12+\n\x11htlc_minimum_msat\x18\x01 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12+\n\x11htlc_maximum_msat\x18\x02 \x01(\x0b\x32\x0b.cln.AmountH\x01\x88\x01\x01\x12\x1e\n\x11\x63ltv_expiry_delta\x18\x03 \x01(\rH\x02\x88\x01\x01\x12\'\n\rfee_base_msat\x18\x04 \x01(\x0b\x32\x0b.cln.AmountH\x03\x88\x01\x01\x12(\n\x1b\x66\x65\x65_proportional_millionths\x18\x05 \x01(\rH\x04\x88\x01\x01\x42\x14\n\x12_htlc_minimum_msatB\x14\n\x12_htlc_maximum_msatB\x14\n\x12_cltv_expiry_deltaB\x10\n\x0e_fee_base_msatB\x1e\n\x1c_fee_proportional_millionths\"]\n\x1fListpeerchannelsChannelsFeerate\x12\x12\n\x05perkw\x18\x01 \x01(\rH\x00\x88\x01\x01\x12\x12\n\x05perkb\x18\x02 \x01(\rH\x01\x88\x01\x01\x42\x08\n\x06_perkwB\x08\n\x06_perkb\"\x80\x03\n ListpeerchannelsChannelsInflight\x12\x19\n\x0c\x66unding_txid\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x12\x1b\n\x0e\x66unding_outnum\x18\x02 \x01(\rH\x01\x88\x01\x01\x12\x14\n\x07\x66\x65\x65rate\x18\x03 \x01(\tH\x02\x88\x01\x01\x12,\n\x12total_funding_msat\x18\x04 \x01(\x0b\x32\x0b.cln.AmountH\x03\x88\x01\x01\x12\x1a\n\rsplice_amount\x18\x07 \x01(\x12H\x04\x88\x01\x01\x12*\n\x10our_funding_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x05\x88\x01\x01\x12\x19\n\x0cscratch_txid\x18\x06 \x01(\x0cH\x06\x88\x01\x01\x42\x0f\n\r_funding_txidB\x11\n\x0f_funding_outnumB\n\n\x08_feerateB\x15\n\x13_total_funding_msatB\x10\n\x0e_splice_amountB\x13\n\x11_our_funding_msatB\x0f\n\r_scratch_txid\"\xd2\x02\n\x1fListpeerchannelsChannelsFunding\x12%\n\x0bpushed_msat\x18\x01 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12*\n\x10local_funds_msat\x18\x02 \x01(\x0b\x32\x0b.cln.AmountH\x01\x88\x01\x01\x12+\n\x11remote_funds_msat\x18\x03 \x01(\x0b\x32\x0b.cln.AmountH\x02\x88\x01\x01\x12\'\n\rfee_paid_msat\x18\x04 \x01(\x0b\x32\x0b.cln.AmountH\x03\x88\x01\x01\x12\'\n\rfee_rcvd_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x04\x88\x01\x01\x42\x0e\n\x0c_pushed_msatB\x13\n\x11_local_funds_msatB\x14\n\x12_remote_funds_msatB\x10\n\x0e_fee_paid_msatB\x10\n\x0e_fee_rcvd_msat\"]\n\x1dListpeerchannelsChannelsAlias\x12\x12\n\x05local\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06remote\x18\x02 \x01(\tH\x01\x88\x01\x01\x42\x08\n\x06_localB\t\n\x07_remote\"\xe2\x03\n\x1dListpeerchannelsChannelsHtlcs\x12\x61\n\tdirection\x18\x01 \x01(\x0e\x32I.cln.ListpeerchannelsChannelsHtlcs.ListpeerchannelsChannelsHtlcsDirectionH\x00\x88\x01\x01\x12\x0f\n\x02id\x18\x02 \x01(\x04H\x01\x88\x01\x01\x12%\n\x0b\x61mount_msat\x18\x03 \x01(\x0b\x32\x0b.cln.AmountH\x02\x88\x01\x01\x12\x13\n\x06\x65xpiry\x18\x04 \x01(\rH\x03\x88\x01\x01\x12\x19\n\x0cpayment_hash\x18\x05 \x01(\x0cH\x04\x88\x01\x01\x12\x1a\n\rlocal_trimmed\x18\x06 \x01(\x08H\x05\x88\x01\x01\x12\x13\n\x06status\x18\x07 \x01(\tH\x06\x88\x01\x01\x12\"\n\x05state\x18\x08 \x01(\x0e\x32\x0e.cln.HtlcStateH\x07\x88\x01\x01\"9\n&ListpeerchannelsChannelsHtlcsDirection\x12\x06\n\x02IN\x10\x00\x12\x07\n\x03OUT\x10\x01\x42\x0c\n\n_directionB\x05\n\x03_idB\x0e\n\x0c_amount_msatB\t\n\x07_expiryB\x0f\n\r_payment_hashB\x10\n\x0e_local_trimmedB\t\n\x07_statusB\x08\n\x06_state\"3\n\x19ListclosedchannelsRequest\x12\x0f\n\x02id\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x42\x05\n\x03_id\"[\n\x1aListclosedchannelsResponse\x12=\n\x0e\x63losedchannels\x18\x01 \x03(\x0b\x32%.cln.ListclosedchannelsClosedchannels\"\xb2\t\n ListclosedchannelsClosedchannels\x12\x14\n\x07peer_id\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x12\x12\n\nchannel_id\x18\x02 \x01(\x0c\x12\x1d\n\x10short_channel_id\x18\x03 \x01(\tH\x01\x88\x01\x01\x12>\n\x05\x61lias\x18\x04 \x01(\x0b\x32*.cln.ListclosedchannelsClosedchannelsAliasH\x02\x88\x01\x01\x12 \n\x06opener\x18\x05 \x01(\x0e\x32\x10.cln.ChannelSide\x12%\n\x06\x63loser\x18\x06 \x01(\x0e\x32\x10.cln.ChannelSideH\x03\x88\x01\x01\x12\x0f\n\x07private\x18\x07 \x01(\x08\x12\x1f\n\x17total_local_commitments\x18\t \x01(\x04\x12 \n\x18total_remote_commitments\x18\n \x01(\x04\x12\x18\n\x10total_htlcs_sent\x18\x0b \x01(\x04\x12\x14\n\x0c\x66unding_txid\x18\x0c \x01(\x0c\x12\x16\n\x0e\x66unding_outnum\x18\r \x01(\r\x12\x0e\n\x06leased\x18\x0e \x01(\x08\x12/\n\x15\x66unding_fee_paid_msat\x18\x0f \x01(\x0b\x32\x0b.cln.AmountH\x04\x88\x01\x01\x12/\n\x15\x66unding_fee_rcvd_msat\x18\x10 \x01(\x0b\x32\x0b.cln.AmountH\x05\x88\x01\x01\x12-\n\x13\x66unding_pushed_msat\x18\x11 \x01(\x0b\x32\x0b.cln.AmountH\x06\x88\x01\x01\x12\x1f\n\ntotal_msat\x18\x12 \x01(\x0b\x32\x0b.cln.Amount\x12%\n\x10\x66inal_to_us_msat\x18\x13 \x01(\x0b\x32\x0b.cln.Amount\x12#\n\x0emin_to_us_msat\x18\x14 \x01(\x0b\x32\x0b.cln.Amount\x12#\n\x0emax_to_us_msat\x18\x15 \x01(\x0b\x32\x0b.cln.Amount\x12!\n\x14last_commitment_txid\x18\x16 \x01(\x0cH\x07\x88\x01\x01\x12\x32\n\x18last_commitment_fee_msat\x18\x17 \x01(\x0b\x32\x0b.cln.AmountH\x08\x88\x01\x01\x12\x66\n\x0b\x63lose_cause\x18\x18 \x01(\x0e\x32Q.cln.ListclosedchannelsClosedchannels.ListclosedchannelsClosedchannelsClose_cause\"v\n+ListclosedchannelsClosedchannelsClose_cause\x12\x0b\n\x07UNKNOWN\x10\x00\x12\t\n\x05LOCAL\x10\x01\x12\x08\n\x04USER\x10\x02\x12\n\n\x06REMOTE\x10\x03\x12\x0c\n\x08PROTOCOL\x10\x04\x12\x0b\n\x07ONCHAIN\x10\x05\x42\n\n\x08_peer_idB\x13\n\x11_short_channel_idB\x08\n\x06_aliasB\t\n\x07_closerB\x18\n\x16_funding_fee_paid_msatB\x18\n\x16_funding_fee_rcvd_msatB\x16\n\x14_funding_pushed_msatB\x17\n\x15_last_commitment_txidB\x1b\n\x19_last_commitment_fee_msat\"e\n%ListclosedchannelsClosedchannelsAlias\x12\x12\n\x05local\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06remote\x18\x02 \x01(\tH\x01\x88\x01\x01\x42\x08\n\x06_localB\t\n\x07_remote\"L\n\x10\x44\x65\x63odepayRequest\x12\x0e\n\x06\x62olt11\x18\x01 \x01(\t\x12\x18\n\x0b\x64\x65scription\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_description\"\x8d\x04\n\x11\x44\x65\x63odepayResponse\x12\x10\n\x08\x63urrency\x18\x01 \x01(\t\x12\x12\n\ncreated_at\x18\x02 \x01(\x04\x12\x0e\n\x06\x65xpiry\x18\x03 \x01(\x04\x12\r\n\x05payee\x18\x04 \x01(\x0c\x12%\n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x06 \x01(\x0c\x12\x11\n\tsignature\x18\x07 \x01(\t\x12\x18\n\x0b\x64\x65scription\x18\x08 \x01(\tH\x01\x88\x01\x01\x12\x1d\n\x10\x64\x65scription_hash\x18\t \x01(\x0cH\x02\x88\x01\x01\x12\x1d\n\x15min_final_cltv_expiry\x18\n \x01(\r\x12\x1b\n\x0epayment_secret\x18\x0b \x01(\x0cH\x03\x88\x01\x01\x12\x15\n\x08\x66\x65\x61tures\x18\x0c \x01(\x0cH\x04\x88\x01\x01\x12\x1d\n\x10payment_metadata\x18\r \x01(\x0cH\x05\x88\x01\x01\x12*\n\tfallbacks\x18\x0e \x03(\x0b\x32\x17.cln.DecodepayFallbacks\x12\"\n\x05\x65xtra\x18\x10 \x03(\x0b\x32\x13.cln.DecodepayExtraB\x0e\n\x0c_amount_msatB\x0e\n\x0c_descriptionB\x13\n\x11_description_hashB\x11\n\x0f_payment_secretB\x0b\n\t_featuresB\x13\n\x11_payment_metadata\"\xd0\x01\n\x12\x44\x65\x63odepayFallbacks\x12\x41\n\titem_type\x18\x01 \x01(\x0e\x32..cln.DecodepayFallbacks.DecodepayFallbacksType\x12\x11\n\x04\x61\x64\x64r\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x0b\n\x03hex\x18\x03 \x01(\x0c\"N\n\x16\x44\x65\x63odepayFallbacksType\x12\t\n\x05P2PKH\x10\x00\x12\x08\n\x04P2SH\x10\x01\x12\n\n\x06P2WPKH\x10\x02\x12\t\n\x05P2WSH\x10\x03\x12\x08\n\x04P2TR\x10\x04\x42\x07\n\x05_addr\"+\n\x0e\x44\x65\x63odepayExtra\x12\x0b\n\x03tag\x18\x01 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\t\"\x1f\n\rDecodeRequest\x12\x0e\n\x06string\x18\x01 \x01(\t\"\xe8!\n\x0e\x44\x65\x63odeResponse\x12\x31\n\titem_type\x18\x01 \x01(\x0e\x32\x1e.cln.DecodeResponse.DecodeType\x12\r\n\x05valid\x18\x02 \x01(\x08\x12\x15\n\x08offer_id\x18\x03 \x01(\x0cH\x00\x88\x01\x01\x12\x14\n\x0coffer_chains\x18\x04 \x03(\x0c\x12\x1b\n\x0eoffer_metadata\x18\x05 \x01(\x0cH\x01\x88\x01\x01\x12\x1b\n\x0eoffer_currency\x18\x06 \x01(\tH\x02\x88\x01\x01\x12+\n\x1ewarning_unknown_offer_currency\x18\x07 \x01(\tH\x03\x88\x01\x01\x12 \n\x13\x63urrency_minor_unit\x18\x08 \x01(\rH\x04\x88\x01\x01\x12\x19\n\x0coffer_amount\x18\t \x01(\x04H\x05\x88\x01\x01\x12+\n\x11offer_amount_msat\x18\n \x01(\x0b\x32\x0b.cln.AmountH\x06\x88\x01\x01\x12\x1e\n\x11offer_description\x18\x0b \x01(\tH\x07\x88\x01\x01\x12\x19\n\x0coffer_issuer\x18\x0c \x01(\tH\x08\x88\x01\x01\x12\x1b\n\x0eoffer_features\x18\r \x01(\x0cH\t\x88\x01\x01\x12\"\n\x15offer_absolute_expiry\x18\x0e \x01(\x04H\n\x88\x01\x01\x12\x1f\n\x12offer_quantity_max\x18\x0f \x01(\x04H\x0b\x88\x01\x01\x12+\n\x0boffer_paths\x18\x10 \x03(\x0b\x32\x16.cln.DecodeOffer_paths\x12\x1a\n\roffer_node_id\x18\x11 \x01(\x0cH\x0c\x88\x01\x01\x12*\n\x1dwarning_missing_offer_node_id\x18\x14 \x01(\tH\r\x88\x01\x01\x12.\n!warning_invalid_offer_description\x18\x15 \x01(\tH\x0e\x88\x01\x01\x12.\n!warning_missing_offer_description\x18\x16 \x01(\tH\x0f\x88\x01\x01\x12+\n\x1ewarning_invalid_offer_currency\x18\x17 \x01(\tH\x10\x88\x01\x01\x12)\n\x1cwarning_invalid_offer_issuer\x18\x18 \x01(\tH\x11\x88\x01\x01\x12\x1c\n\x0finvreq_metadata\x18\x19 \x01(\x0cH\x12\x88\x01\x01\x12\x1c\n\x0finvreq_payer_id\x18\x1a \x01(\x0cH\x13\x88\x01\x01\x12\x19\n\x0cinvreq_chain\x18\x1b \x01(\x0cH\x14\x88\x01\x01\x12,\n\x12invreq_amount_msat\x18\x1c \x01(\x0b\x32\x0b.cln.AmountH\x15\x88\x01\x01\x12\x1c\n\x0finvreq_features\x18\x1d \x01(\x0cH\x16\x88\x01\x01\x12\x1c\n\x0finvreq_quantity\x18\x1e \x01(\x04H\x17\x88\x01\x01\x12\x1e\n\x11invreq_payer_note\x18\x1f \x01(\tH\x18\x88\x01\x01\x12&\n\x19invreq_recurrence_counter\x18 \x01(\rH\x19\x88\x01\x01\x12$\n\x17invreq_recurrence_start\x18! \x01(\rH\x1a\x88\x01\x01\x12,\n\x1fwarning_missing_invreq_metadata\x18# \x01(\tH\x1b\x88\x01\x01\x12,\n\x1fwarning_missing_invreq_payer_id\x18$ \x01(\tH\x1c\x88\x01\x01\x12.\n!warning_invalid_invreq_payer_note\x18% \x01(\tH\x1d\x88\x01\x01\x12\x36\n)warning_missing_invoice_request_signature\x18& \x01(\tH\x1e\x88\x01\x01\x12\x36\n)warning_invalid_invoice_request_signature\x18\' \x01(\tH\x1f\x88\x01\x01\x12\x1f\n\x12invoice_created_at\x18) \x01(\x04H \x88\x01\x01\x12$\n\x17invoice_relative_expiry\x18* \x01(\rH!\x88\x01\x01\x12!\n\x14invoice_payment_hash\x18+ \x01(\x0cH\"\x88\x01\x01\x12-\n\x13invoice_amount_msat\x18, \x01(\x0b\x32\x0b.cln.AmountH#\x88\x01\x01\x12\x37\n\x11invoice_fallbacks\x18- \x03(\x0b\x32\x1c.cln.DecodeInvoice_fallbacks\x12\x1d\n\x10invoice_features\x18. \x01(\x0cH$\x88\x01\x01\x12\x1c\n\x0finvoice_node_id\x18/ \x01(\x0cH%\x88\x01\x01\x12(\n\x1binvoice_recurrence_basetime\x18\x30 \x01(\x04H&\x88\x01\x01\x12*\n\x1dwarning_missing_invoice_paths\x18\x32 \x01(\tH\'\x88\x01\x01\x12/\n\"warning_missing_invoice_blindedpay\x18\x33 \x01(\tH(\x88\x01\x01\x12/\n\"warning_missing_invoice_created_at\x18\x34 \x01(\tH)\x88\x01\x01\x12\x31\n$warning_missing_invoice_payment_hash\x18\x35 \x01(\tH*\x88\x01\x01\x12+\n\x1ewarning_missing_invoice_amount\x18\x36 \x01(\tH+\x88\x01\x01\x12\x38\n+warning_missing_invoice_recurrence_basetime\x18\x37 \x01(\tH,\x88\x01\x01\x12,\n\x1fwarning_missing_invoice_node_id\x18\x38 \x01(\tH-\x88\x01\x01\x12.\n!warning_missing_invoice_signature\x18\x39 \x01(\tH.\x88\x01\x01\x12.\n!warning_invalid_invoice_signature\x18: \x01(\tH/\x88\x01\x01\x12\'\n\tfallbacks\x18; \x03(\x0b\x32\x14.cln.DecodeFallbacks\x12\x17\n\ncreated_at\x18< \x01(\x04H0\x88\x01\x01\x12\x13\n\x06\x65xpiry\x18= \x01(\x04H1\x88\x01\x01\x12\x12\n\x05payee\x18> \x01(\x0cH2\x88\x01\x01\x12\x19\n\x0cpayment_hash\x18? \x01(\x0cH3\x88\x01\x01\x12\x1d\n\x10\x64\x65scription_hash\x18@ \x01(\x0cH4\x88\x01\x01\x12\"\n\x15min_final_cltv_expiry\x18\x41 \x01(\rH5\x88\x01\x01\x12\x1b\n\x0epayment_secret\x18\x42 \x01(\x0cH6\x88\x01\x01\x12\x1d\n\x10payment_metadata\x18\x43 \x01(\x0cH7\x88\x01\x01\x12\x1f\n\x05\x65xtra\x18\x45 \x03(\x0b\x32\x10.cln.DecodeExtra\x12\x16\n\tunique_id\x18\x46 \x01(\tH8\x88\x01\x01\x12\x14\n\x07version\x18G \x01(\tH9\x88\x01\x01\x12\x13\n\x06string\x18H \x01(\tH:\x88\x01\x01\x12-\n\x0crestrictions\x18I \x03(\x0b\x32\x17.cln.DecodeRestrictions\x12&\n\x19warning_rune_invalid_utf8\x18J \x01(\tH;\x88\x01\x01\x12\x10\n\x03hex\x18K \x01(\x0cH<\x88\x01\x01\x12\x16\n\tdecrypted\x18L \x01(\x0cH=\x88\x01\x01\"\x83\x01\n\nDecodeType\x12\x10\n\x0c\x42OLT12_OFFER\x10\x00\x12\x12\n\x0e\x42OLT12_INVOICE\x10\x01\x12\x1a\n\x16\x42OLT12_INVOICE_REQUEST\x10\x02\x12\x12\n\x0e\x42OLT11_INVOICE\x10\x03\x12\x08\n\x04RUNE\x10\x04\x12\x15\n\x11\x45MERGENCY_RECOVER\x10\x05\x42\x0b\n\t_offer_idB\x11\n\x0f_offer_metadataB\x11\n\x0f_offer_currencyB!\n\x1f_warning_unknown_offer_currencyB\x16\n\x14_currency_minor_unitB\x0f\n\r_offer_amountB\x14\n\x12_offer_amount_msatB\x14\n\x12_offer_descriptionB\x0f\n\r_offer_issuerB\x11\n\x0f_offer_featuresB\x18\n\x16_offer_absolute_expiryB\x15\n\x13_offer_quantity_maxB\x10\n\x0e_offer_node_idB \n\x1e_warning_missing_offer_node_idB$\n\"_warning_invalid_offer_descriptionB$\n\"_warning_missing_offer_descriptionB!\n\x1f_warning_invalid_offer_currencyB\x1f\n\x1d_warning_invalid_offer_issuerB\x12\n\x10_invreq_metadataB\x12\n\x10_invreq_payer_idB\x0f\n\r_invreq_chainB\x15\n\x13_invreq_amount_msatB\x12\n\x10_invreq_featuresB\x12\n\x10_invreq_quantityB\x14\n\x12_invreq_payer_noteB\x1c\n\x1a_invreq_recurrence_counterB\x1a\n\x18_invreq_recurrence_startB\"\n _warning_missing_invreq_metadataB\"\n _warning_missing_invreq_payer_idB$\n\"_warning_invalid_invreq_payer_noteB,\n*_warning_missing_invoice_request_signatureB,\n*_warning_invalid_invoice_request_signatureB\x15\n\x13_invoice_created_atB\x1a\n\x18_invoice_relative_expiryB\x17\n\x15_invoice_payment_hashB\x16\n\x14_invoice_amount_msatB\x13\n\x11_invoice_featuresB\x12\n\x10_invoice_node_idB\x1e\n\x1c_invoice_recurrence_basetimeB \n\x1e_warning_missing_invoice_pathsB%\n#_warning_missing_invoice_blindedpayB%\n#_warning_missing_invoice_created_atB\'\n%_warning_missing_invoice_payment_hashB!\n\x1f_warning_missing_invoice_amountB.\n,_warning_missing_invoice_recurrence_basetimeB\"\n _warning_missing_invoice_node_idB$\n\"_warning_missing_invoice_signatureB$\n\"_warning_invalid_invoice_signatureB\r\n\x0b_created_atB\t\n\x07_expiryB\x08\n\x06_payeeB\x0f\n\r_payment_hashB\x13\n\x11_description_hashB\x18\n\x16_min_final_cltv_expiryB\x11\n\x0f_payment_secretB\x13\n\x11_payment_metadataB\x0c\n\n_unique_idB\n\n\x08_versionB\t\n\x07_stringB\x1c\n\x1a_warning_rune_invalid_utf8B\x06\n\x04_hexB\x0c\n\n_decrypted\"<\n\x11\x44\x65\x63odeOffer_paths\x12\x15\n\rfirst_node_id\x18\x01 \x01(\x0c\x12\x10\n\x08\x62linding\x18\x02 \x01(\x0c\"\x8a\x01\n\x1f\x44\x65\x63odeOffer_recurrencePaywindow\x12\x16\n\x0eseconds_before\x18\x01 \x01(\r\x12\x15\n\rseconds_after\x18\x02 \x01(\r\x12 \n\x13proportional_amount\x18\x03 \x01(\x08H\x00\x88\x01\x01\x42\x16\n\x14_proportional_amount\"T\n\x17\x44\x65\x63odeInvoice_pathsPath\x12\x17\n\x0f\x62linded_node_id\x18\x01 \x01(\x0c\x12 \n\x18\x65ncrypted_recipient_data\x18\x02 \x01(\x0c\"Y\n\x17\x44\x65\x63odeInvoice_fallbacks\x12\x0f\n\x07version\x18\x01 \x01(\r\x12\x0b\n\x03hex\x18\x02 \x01(\x0c\x12\x14\n\x07\x61\x64\x64ress\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\n\n\x08_address\"w\n\x0f\x44\x65\x63odeFallbacks\x12\x36\n)warning_invoice_fallbacks_version_invalid\x18\x01 \x01(\tH\x00\x88\x01\x01\x42,\n*_warning_invoice_fallbacks_version_invalid\"(\n\x0b\x44\x65\x63odeExtra\x12\x0b\n\x03tag\x18\x01 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\t\";\n\x12\x44\x65\x63odeRestrictions\x12\x14\n\x0c\x61lternatives\x18\x01 \x03(\t\x12\x0f\n\x07summary\x18\x02 \x01(\t\"=\n\x11\x44isconnectRequest\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x12\n\x05\x66orce\x18\x02 \x01(\x08H\x00\x88\x01\x01\x42\x08\n\x06_force\"\x14\n\x12\x44isconnectResponse\"k\n\x0f\x46\x65\x65ratesRequest\x12\x31\n\x05style\x18\x01 \x01(\x0e\x32\".cln.FeeratesRequest.FeeratesStyle\"%\n\rFeeratesStyle\x12\t\n\x05PERKB\x10\x00\x12\t\n\x05PERKW\x10\x01\"\x9c\x02\n\x10\x46\x65\x65ratesResponse\x12%\n\x18warning_missing_feerates\x18\x01 \x01(\tH\x00\x88\x01\x01\x12&\n\x05perkb\x18\x02 \x01(\x0b\x32\x12.cln.FeeratesPerkbH\x01\x88\x01\x01\x12&\n\x05perkw\x18\x03 \x01(\x0b\x32\x12.cln.FeeratesPerkwH\x02\x88\x01\x01\x12\x46\n\x15onchain_fee_estimates\x18\x04 \x01(\x0b\x32\".cln.FeeratesOnchain_fee_estimatesH\x03\x88\x01\x01\x42\x1b\n\x19_warning_missing_feeratesB\x08\n\x06_perkbB\x08\n\x06_perkwB\x18\n\x16_onchain_fee_estimates\"\xd3\x03\n\rFeeratesPerkb\x12\x16\n\x0emin_acceptable\x18\x01 \x01(\r\x12\x16\n\x0emax_acceptable\x18\x02 \x01(\r\x12\x12\n\x05\x66loor\x18\n \x01(\rH\x00\x88\x01\x01\x12.\n\testimates\x18\t \x03(\x0b\x32\x1b.cln.FeeratesPerkbEstimates\x12\x14\n\x07opening\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\x19\n\x0cmutual_close\x18\x04 \x01(\rH\x02\x88\x01\x01\x12\x1d\n\x10unilateral_close\x18\x05 \x01(\rH\x03\x88\x01\x01\x12$\n\x17unilateral_anchor_close\x18\x0b \x01(\rH\x04\x88\x01\x01\x12\x1a\n\rdelayed_to_us\x18\x06 \x01(\rH\x05\x88\x01\x01\x12\x1c\n\x0fhtlc_resolution\x18\x07 \x01(\rH\x06\x88\x01\x01\x12\x14\n\x07penalty\x18\x08 \x01(\rH\x07\x88\x01\x01\x42\x08\n\x06_floorB\n\n\x08_openingB\x0f\n\r_mutual_closeB\x13\n\x11_unilateral_closeB\x1a\n\x18_unilateral_anchor_closeB\x10\n\x0e_delayed_to_usB\x12\n\x10_htlc_resolutionB\n\n\x08_penalty\"\x96\x01\n\x16\x46\x65\x65ratesPerkbEstimates\x12\x17\n\nblockcount\x18\x01 \x01(\rH\x00\x88\x01\x01\x12\x14\n\x07\x66\x65\x65rate\x18\x02 \x01(\rH\x01\x88\x01\x01\x12\x1d\n\x10smoothed_feerate\x18\x03 \x01(\rH\x02\x88\x01\x01\x42\r\n\x0b_blockcountB\n\n\x08_feerateB\x13\n\x11_smoothed_feerate\"\xd3\x03\n\rFeeratesPerkw\x12\x16\n\x0emin_acceptable\x18\x01 \x01(\r\x12\x16\n\x0emax_acceptable\x18\x02 \x01(\r\x12\x12\n\x05\x66loor\x18\n \x01(\rH\x00\x88\x01\x01\x12.\n\testimates\x18\t \x03(\x0b\x32\x1b.cln.FeeratesPerkwEstimates\x12\x14\n\x07opening\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\x19\n\x0cmutual_close\x18\x04 \x01(\rH\x02\x88\x01\x01\x12\x1d\n\x10unilateral_close\x18\x05 \x01(\rH\x03\x88\x01\x01\x12$\n\x17unilateral_anchor_close\x18\x0b \x01(\rH\x04\x88\x01\x01\x12\x1a\n\rdelayed_to_us\x18\x06 \x01(\rH\x05\x88\x01\x01\x12\x1c\n\x0fhtlc_resolution\x18\x07 \x01(\rH\x06\x88\x01\x01\x12\x14\n\x07penalty\x18\x08 \x01(\rH\x07\x88\x01\x01\x42\x08\n\x06_floorB\n\n\x08_openingB\x0f\n\r_mutual_closeB\x13\n\x11_unilateral_closeB\x1a\n\x18_unilateral_anchor_closeB\x10\n\x0e_delayed_to_usB\x12\n\x10_htlc_resolutionB\n\n\x08_penalty\"\x96\x01\n\x16\x46\x65\x65ratesPerkwEstimates\x12\x17\n\nblockcount\x18\x01 \x01(\rH\x00\x88\x01\x01\x12\x14\n\x07\x66\x65\x65rate\x18\x02 \x01(\rH\x01\x88\x01\x01\x12\x1d\n\x10smoothed_feerate\x18\x03 \x01(\rH\x02\x88\x01\x01\x42\r\n\x0b_blockcountB\n\n\x08_feerateB\x13\n\x11_smoothed_feerate\"\x9b\x02\n\x1d\x46\x65\x65ratesOnchain_fee_estimates\x12 \n\x18opening_channel_satoshis\x18\x01 \x01(\x04\x12\x1d\n\x15mutual_close_satoshis\x18\x02 \x01(\x04\x12!\n\x19unilateral_close_satoshis\x18\x03 \x01(\x04\x12\x30\n#unilateral_close_nonanchor_satoshis\x18\x06 \x01(\x04H\x00\x88\x01\x01\x12\x1d\n\x15htlc_timeout_satoshis\x18\x04 \x01(\x04\x12\x1d\n\x15htlc_success_satoshis\x18\x05 \x01(\x04\x42&\n$_unilateral_close_nonanchor_satoshis\"\xe9\x02\n\x13\x46\x65tchinvoiceRequest\x12\r\n\x05offer\x18\x01 \x01(\t\x12%\n\x0b\x61mount_msat\x18\x02 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12\x15\n\x08quantity\x18\x03 \x01(\x04H\x01\x88\x01\x01\x12\x1f\n\x12recurrence_counter\x18\x04 \x01(\x04H\x02\x88\x01\x01\x12\x1d\n\x10recurrence_start\x18\x05 \x01(\x01H\x03\x88\x01\x01\x12\x1d\n\x10recurrence_label\x18\x06 \x01(\tH\x04\x88\x01\x01\x12\x14\n\x07timeout\x18\x07 \x01(\x01H\x05\x88\x01\x01\x12\x17\n\npayer_note\x18\x08 \x01(\tH\x06\x88\x01\x01\x42\x0e\n\x0c_amount_msatB\x0b\n\t_quantityB\x15\n\x13_recurrence_counterB\x13\n\x11_recurrence_startB\x13\n\x11_recurrence_labelB\n\n\x08_timeoutB\r\n\x0b_payer_note\"\x9a\x01\n\x14\x46\x65tchinvoiceResponse\x12\x0f\n\x07invoice\x18\x01 \x01(\t\x12)\n\x07\x63hanges\x18\x02 \x01(\x0b\x32\x18.cln.FetchinvoiceChanges\x12\x36\n\x0bnext_period\x18\x03 \x01(\x0b\x32\x1c.cln.FetchinvoiceNext_periodH\x00\x88\x01\x01\x42\x0e\n\x0c_next_period\"\x82\x02\n\x13\x46\x65tchinvoiceChanges\x12!\n\x14\x64\x65scription_appended\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x18\n\x0b\x64\x65scription\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x1b\n\x0evendor_removed\x18\x03 \x01(\tH\x02\x88\x01\x01\x12\x13\n\x06vendor\x18\x04 \x01(\tH\x03\x88\x01\x01\x12%\n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x04\x88\x01\x01\x42\x17\n\x15_description_appendedB\x0e\n\x0c_descriptionB\x11\n\x0f_vendor_removedB\t\n\x07_vendorB\x0e\n\x0c_amount_msat\"~\n\x17\x46\x65tchinvoiceNext_period\x12\x0f\n\x07\x63ounter\x18\x01 \x01(\x04\x12\x11\n\tstarttime\x18\x02 \x01(\x04\x12\x0f\n\x07\x65ndtime\x18\x03 \x01(\x04\x12\x17\n\x0fpaywindow_start\x18\x04 \x01(\x04\x12\x15\n\rpaywindow_end\x18\x05 \x01(\x04\"\xfb\x03\n\x12\x46undchannelRequest\x12\n\n\x02id\x18\t \x01(\x0c\x12 \n\x06\x61mount\x18\x01 \x01(\x0b\x32\x10.cln.AmountOrAll\x12\"\n\x07\x66\x65\x65rate\x18\x02 \x01(\x0b\x32\x0c.cln.FeerateH\x00\x88\x01\x01\x12\x15\n\x08\x61nnounce\x18\x03 \x01(\x08H\x01\x88\x01\x01\x12\x14\n\x07minconf\x18\n \x01(\rH\x02\x88\x01\x01\x12#\n\tpush_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x03\x88\x01\x01\x12\x15\n\x08\x63lose_to\x18\x06 \x01(\tH\x04\x88\x01\x01\x12%\n\x0brequest_amt\x18\x07 \x01(\x0b\x32\x0b.cln.AmountH\x05\x88\x01\x01\x12\x1a\n\rcompact_lease\x18\x08 \x01(\tH\x06\x88\x01\x01\x12\x1c\n\x05utxos\x18\x0b \x03(\x0b\x32\r.cln.Outpoint\x12\x15\n\x08mindepth\x18\x0c \x01(\rH\x07\x88\x01\x01\x12!\n\x07reserve\x18\r \x01(\x0b\x32\x0b.cln.AmountH\x08\x88\x01\x01\x12\x14\n\x0c\x63hannel_type\x18\x0e \x03(\rB\n\n\x08_feerateB\x0b\n\t_announceB\n\n\x08_minconfB\x0c\n\n_push_msatB\x0b\n\t_close_toB\x0e\n\x0c_request_amtB\x10\n\x0e_compact_leaseB\x0b\n\t_mindepthB\n\n\x08_reserve\"\xe5\x01\n\x13\x46undchannelResponse\x12\n\n\x02tx\x18\x01 \x01(\x0c\x12\x0c\n\x04txid\x18\x02 \x01(\x0c\x12\x0e\n\x06outnum\x18\x03 \x01(\r\x12\x12\n\nchannel_id\x18\x04 \x01(\x0c\x12\x37\n\x0c\x63hannel_type\x18\x07 \x01(\x0b\x32\x1c.cln.FundchannelChannel_typeH\x00\x88\x01\x01\x12\x15\n\x08\x63lose_to\x18\x05 \x01(\x0cH\x01\x88\x01\x01\x12\x15\n\x08mindepth\x18\x06 \x01(\rH\x02\x88\x01\x01\x42\x0f\n\r_channel_typeB\x0b\n\t_close_toB\x0b\n\t_mindepth\"L\n\x17\x46undchannelChannel_type\x12\x0c\n\x04\x62its\x18\x01 \x03(\r\x12#\n\x05names\x18\x02 \x03(\x0e\x32\x14.cln.ChannelTypeName\"\xec\x01\n\x0fGetrouteRequest\x12\n\n\x02id\x18\x01 \x01(\x0c\x12 \n\x0b\x61mount_msat\x18\t \x01(\x0b\x32\x0b.cln.Amount\x12\x12\n\nriskfactor\x18\x03 \x01(\x04\x12\x11\n\x04\x63ltv\x18\x04 \x01(\rH\x00\x88\x01\x01\x12\x13\n\x06\x66romid\x18\x05 \x01(\x0cH\x01\x88\x01\x01\x12\x18\n\x0b\x66uzzpercent\x18\x06 \x01(\rH\x02\x88\x01\x01\x12\x0f\n\x07\x65xclude\x18\x07 \x03(\t\x12\x14\n\x07maxhops\x18\x08 \x01(\rH\x03\x88\x01\x01\x42\x07\n\x05_cltvB\t\n\x07_fromidB\x0e\n\x0c_fuzzpercentB\n\n\x08_maxhops\"5\n\x10GetrouteResponse\x12!\n\x05route\x18\x01 \x03(\x0b\x32\x12.cln.GetrouteRoute\"\xc5\x01\n\rGetrouteRoute\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x0f\n\x07\x63hannel\x18\x02 \x01(\t\x12\x11\n\tdirection\x18\x03 \x01(\r\x12 \n\x0b\x61mount_msat\x18\x04 \x01(\x0b\x32\x0b.cln.Amount\x12\r\n\x05\x64\x65lay\x18\x05 \x01(\r\x12\x34\n\x05style\x18\x06 \x01(\x0e\x32%.cln.GetrouteRoute.GetrouteRouteStyle\"\x1d\n\x12GetrouteRouteStyle\x12\x07\n\x03TLV\x10\x00\"\xb7\x03\n\x13ListforwardsRequest\x12@\n\x06status\x18\x01 \x01(\x0e\x32+.cln.ListforwardsRequest.ListforwardsStatusH\x00\x88\x01\x01\x12\x17\n\nin_channel\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x18\n\x0bout_channel\x18\x03 \x01(\tH\x02\x88\x01\x01\x12>\n\x05index\x18\x04 \x01(\x0e\x32*.cln.ListforwardsRequest.ListforwardsIndexH\x03\x88\x01\x01\x12\x12\n\x05start\x18\x05 \x01(\x04H\x04\x88\x01\x01\x12\x12\n\x05limit\x18\x06 \x01(\rH\x05\x88\x01\x01\"L\n\x12ListforwardsStatus\x12\x0b\n\x07OFFERED\x10\x00\x12\x0b\n\x07SETTLED\x10\x01\x12\x10\n\x0cLOCAL_FAILED\x10\x02\x12\n\n\x06\x46\x41ILED\x10\x03\"-\n\x11ListforwardsIndex\x12\x0b\n\x07\x43REATED\x10\x00\x12\x0b\n\x07UPDATED\x10\x01\x42\t\n\x07_statusB\r\n\x0b_in_channelB\x0e\n\x0c_out_channelB\x08\n\x06_indexB\x08\n\x06_startB\x08\n\x06_limit\"C\n\x14ListforwardsResponse\x12+\n\x08\x66orwards\x18\x01 \x03(\x0b\x32\x19.cln.ListforwardsForwards\"\xba\x05\n\x14ListforwardsForwards\x12\x1a\n\rcreated_index\x18\x0c \x01(\x04H\x00\x88\x01\x01\x12\x12\n\nin_channel\x18\x01 \x01(\t\x12\x17\n\nin_htlc_id\x18\n \x01(\x04H\x01\x88\x01\x01\x12\x1c\n\x07in_msat\x18\x02 \x01(\x0b\x32\x0b.cln.Amount\x12\x44\n\x06status\x18\x03 \x01(\x0e\x32\x34.cln.ListforwardsForwards.ListforwardsForwardsStatus\x12\x15\n\rreceived_time\x18\x04 \x01(\x01\x12\x18\n\x0bout_channel\x18\x05 \x01(\tH\x02\x88\x01\x01\x12\x18\n\x0bout_htlc_id\x18\x0b \x01(\x04H\x03\x88\x01\x01\x12\x1a\n\rupdated_index\x18\r \x01(\x04H\x04\x88\x01\x01\x12G\n\x05style\x18\t \x01(\x0e\x32\x33.cln.ListforwardsForwards.ListforwardsForwardsStyleH\x05\x88\x01\x01\x12\"\n\x08\x66\x65\x65_msat\x18\x07 \x01(\x0b\x32\x0b.cln.AmountH\x06\x88\x01\x01\x12\"\n\x08out_msat\x18\x08 \x01(\x0b\x32\x0b.cln.AmountH\x07\x88\x01\x01\"T\n\x1aListforwardsForwardsStatus\x12\x0b\n\x07OFFERED\x10\x00\x12\x0b\n\x07SETTLED\x10\x01\x12\x10\n\x0cLOCAL_FAILED\x10\x02\x12\n\n\x06\x46\x41ILED\x10\x03\"0\n\x19ListforwardsForwardsStyle\x12\n\n\x06LEGACY\x10\x00\x12\x07\n\x03TLV\x10\x01\x42\x10\n\x0e_created_indexB\r\n\x0b_in_htlc_idB\x0e\n\x0c_out_channelB\x0e\n\x0c_out_htlc_idB\x10\n\x0e_updated_indexB\x08\n\x06_styleB\x0b\n\t_fee_msatB\x0b\n\t_out_msat\"\xdb\x01\n\x0fListpaysRequest\x12\x13\n\x06\x62olt11\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x19\n\x0cpayment_hash\x18\x02 \x01(\x0cH\x01\x88\x01\x01\x12\x38\n\x06status\x18\x03 \x01(\x0e\x32#.cln.ListpaysRequest.ListpaysStatusH\x02\x88\x01\x01\"7\n\x0eListpaysStatus\x12\x0b\n\x07PENDING\x10\x00\x12\x0c\n\x08\x43OMPLETE\x10\x01\x12\n\n\x06\x46\x41ILED\x10\x02\x42\t\n\x07_bolt11B\x0f\n\r_payment_hashB\t\n\x07_status\"3\n\x10ListpaysResponse\x12\x1f\n\x04pays\x18\x01 \x03(\x0b\x32\x11.cln.ListpaysPays\"\xff\x04\n\x0cListpaysPays\x12\x14\n\x0cpayment_hash\x18\x01 \x01(\x0c\x12\x34\n\x06status\x18\x02 \x01(\x0e\x32$.cln.ListpaysPays.ListpaysPaysStatus\x12\x18\n\x0b\x64\x65stination\x18\x03 \x01(\x0cH\x00\x88\x01\x01\x12\x12\n\ncreated_at\x18\x04 \x01(\x04\x12\x19\n\x0c\x63ompleted_at\x18\x0c \x01(\x04H\x01\x88\x01\x01\x12\x12\n\x05label\x18\x05 \x01(\tH\x02\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x06 \x01(\tH\x03\x88\x01\x01\x12\x18\n\x0b\x64\x65scription\x18\x0b \x01(\tH\x04\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x07 \x01(\tH\x05\x88\x01\x01\x12%\n\x0b\x61mount_msat\x18\x08 \x01(\x0b\x32\x0b.cln.AmountH\x06\x88\x01\x01\x12*\n\x10\x61mount_sent_msat\x18\t \x01(\x0b\x32\x0b.cln.AmountH\x07\x88\x01\x01\x12\x15\n\x08preimage\x18\r \x01(\x0cH\x08\x88\x01\x01\x12\x1c\n\x0fnumber_of_parts\x18\x0e \x01(\x04H\t\x88\x01\x01\x12\x17\n\nerroronion\x18\n \x01(\x0cH\n\x88\x01\x01\";\n\x12ListpaysPaysStatus\x12\x0b\n\x07PENDING\x10\x00\x12\n\n\x06\x46\x41ILED\x10\x01\x12\x0c\n\x08\x43OMPLETE\x10\x02\x42\x0e\n\x0c_destinationB\x0f\n\r_completed_atB\x08\n\x06_labelB\t\n\x07_bolt11B\x0e\n\x0c_descriptionB\t\n\x07_bolt12B\x0e\n\x0c_amount_msatB\x13\n\x11_amount_sent_msatB\x0b\n\t_preimageB\x12\n\x10_number_of_partsB\r\n\x0b_erroronion\"*\n\x10ListhtlcsRequest\x12\x0f\n\x02id\x18\x01 \x01(\tH\x00\x88\x01\x01\x42\x05\n\x03_id\"7\n\x11ListhtlcsResponse\x12\"\n\x05htlcs\x18\x01 \x03(\x0b\x32\x13.cln.ListhtlcsHtlcs\"\x89\x02\n\x0eListhtlcsHtlcs\x12\x18\n\x10short_channel_id\x18\x01 \x01(\t\x12\n\n\x02id\x18\x02 \x01(\x04\x12\x0e\n\x06\x65xpiry\x18\x03 \x01(\r\x12 \n\x0b\x61mount_msat\x18\x04 \x01(\x0b\x32\x0b.cln.Amount\x12>\n\tdirection\x18\x05 \x01(\x0e\x32+.cln.ListhtlcsHtlcs.ListhtlcsHtlcsDirection\x12\x14\n\x0cpayment_hash\x18\x06 \x01(\x0c\x12\x1d\n\x05state\x18\x07 \x01(\x0e\x32\x0e.cln.HtlcState\"*\n\x17ListhtlcsHtlcsDirection\x12\x07\n\x03OUT\x10\x00\x12\x06\n\x02IN\x10\x01\"Y\n\x0bPingRequest\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x10\n\x03len\x18\x02 \x01(\rH\x00\x88\x01\x01\x12\x16\n\tpongbytes\x18\x03 \x01(\rH\x01\x88\x01\x01\x42\x06\n\x04_lenB\x0c\n\n_pongbytes\"\x1e\n\x0cPingResponse\x12\x0e\n\x06totlen\x18\x01 \x01(\r\"4\n\x14SendcustommsgRequest\x12\x0f\n\x07node_id\x18\x01 \x01(\x0c\x12\x0b\n\x03msg\x18\x02 \x01(\x0c\"\'\n\x15SendcustommsgResponse\x12\x0e\n\x06status\x18\x01 \x01(\t\"\xaa\x02\n\x11SetchannelRequest\x12\n\n\x02id\x18\x01 \x01(\t\x12!\n\x07\x66\x65\x65\x62\x61se\x18\x02 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12\x13\n\x06\x66\x65\x65ppm\x18\x03 \x01(\rH\x01\x88\x01\x01\x12!\n\x07htlcmin\x18\x04 \x01(\x0b\x32\x0b.cln.AmountH\x02\x88\x01\x01\x12!\n\x07htlcmax\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x03\x88\x01\x01\x12\x19\n\x0c\x65nforcedelay\x18\x06 \x01(\rH\x04\x88\x01\x01\x12\x1c\n\x0fignorefeelimits\x18\x07 \x01(\x08H\x05\x88\x01\x01\x42\n\n\x08_feebaseB\t\n\x07_feeppmB\n\n\x08_htlcminB\n\n\x08_htlcmaxB\x0f\n\r_enforcedelayB\x12\n\x10_ignorefeelimits\"?\n\x12SetchannelResponse\x12)\n\x08\x63hannels\x18\x01 \x03(\x0b\x32\x17.cln.SetchannelChannels\"\xca\x03\n\x12SetchannelChannels\x12\x0f\n\x07peer_id\x18\x01 \x01(\x0c\x12\x12\n\nchannel_id\x18\x02 \x01(\x0c\x12\x1d\n\x10short_channel_id\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\"\n\rfee_base_msat\x18\x04 \x01(\x0b\x32\x0b.cln.Amount\x12#\n\x1b\x66\x65\x65_proportional_millionths\x18\x05 \x01(\r\x12\x1e\n\x11ignore_fee_limits\x18\n \x01(\x08H\x01\x88\x01\x01\x12*\n\x15minimum_htlc_out_msat\x18\x06 \x01(\x0b\x32\x0b.cln.Amount\x12$\n\x17warning_htlcmin_too_low\x18\x07 \x01(\tH\x02\x88\x01\x01\x12*\n\x15maximum_htlc_out_msat\x18\x08 \x01(\x0b\x32\x0b.cln.Amount\x12%\n\x18warning_htlcmax_too_high\x18\t \x01(\tH\x03\x88\x01\x01\x42\x13\n\x11_short_channel_idB\x14\n\x12_ignore_fee_limitsB\x1a\n\x18_warning_htlcmin_too_lowB\x1b\n\x19_warning_htlcmax_too_high\"\'\n\x12SigninvoiceRequest\x12\x11\n\tinvstring\x18\x01 \x01(\t\"%\n\x13SigninvoiceResponse\x12\x0e\n\x06\x62olt11\x18\x01 \x01(\t\"%\n\x12SignmessageRequest\x12\x0f\n\x07message\x18\x01 \x01(\t\"F\n\x13SignmessageResponse\x12\x11\n\tsignature\x18\x01 \x01(\x0c\x12\r\n\x05recid\x18\x02 \x01(\x0c\x12\r\n\x05zbase\x18\x03 \x01(\t\"O\n\x16WaitblockheightRequest\x12\x13\n\x0b\x62lockheight\x18\x01 \x01(\r\x12\x14\n\x07timeout\x18\x02 \x01(\rH\x00\x88\x01\x01\x42\n\n\x08_timeout\".\n\x17WaitblockheightResponse\x12\x13\n\x0b\x62lockheight\x18\x01 \x01(\r\"\xf9\x01\n\x0bWaitRequest\x12\x31\n\tsubsystem\x18\x01 \x01(\x0e\x32\x1e.cln.WaitRequest.WaitSubsystem\x12\x31\n\tindexname\x18\x02 \x01(\x0e\x32\x1e.cln.WaitRequest.WaitIndexname\x12\x11\n\tnextvalue\x18\x03 \x01(\x04\"9\n\rWaitSubsystem\x12\x0c\n\x08INVOICES\x10\x00\x12\x0c\n\x08\x46ORWARDS\x10\x01\x12\x0c\n\x08SENDPAYS\x10\x02\"6\n\rWaitIndexname\x12\x0b\n\x07\x43REATED\x10\x00\x12\x0b\n\x07UPDATED\x10\x01\x12\x0b\n\x07\x44\x45LETED\x10\x02\"\xe3\x01\n\x0cWaitResponse\x12\x32\n\tsubsystem\x18\x01 \x01(\x0e\x32\x1f.cln.WaitResponse.WaitSubsystem\x12\x14\n\x07\x63reated\x18\x02 \x01(\x04H\x00\x88\x01\x01\x12\x14\n\x07updated\x18\x03 \x01(\x04H\x01\x88\x01\x01\x12\x14\n\x07\x64\x65leted\x18\x04 \x01(\x04H\x02\x88\x01\x01\"9\n\rWaitSubsystem\x12\x0c\n\x08INVOICES\x10\x00\x12\x0c\n\x08\x46ORWARDS\x10\x01\x12\x0c\n\x08SENDPAYS\x10\x02\x42\n\n\x08_createdB\n\n\x08_updatedB\n\n\x08_deleted\"\r\n\x0bStopRequest\"\x0e\n\x0cStopResponse\"\xa7\x01\n\x18PreapprovekeysendRequest\x12\x18\n\x0b\x64\x65stination\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x12\x19\n\x0cpayment_hash\x18\x02 \x01(\x0cH\x01\x88\x01\x01\x12%\n\x0b\x61mount_msat\x18\x03 \x01(\x0b\x32\x0b.cln.AmountH\x02\x88\x01\x01\x42\x0e\n\x0c_destinationB\x0f\n\r_payment_hashB\x0e\n\x0c_amount_msat\"\x1b\n\x19PreapprovekeysendResponse\":\n\x18PreapproveinvoiceRequest\x12\x13\n\x06\x62olt11\x18\x01 \x01(\tH\x00\x88\x01\x01\x42\t\n\x07_bolt11\"\x1b\n\x19PreapproveinvoiceResponse\"\x15\n\x13StaticbackupRequest\"#\n\x14StaticbackupResponse\x12\x0b\n\x03scb\x18\x01 \x03(\x0c\x32\xa2\x1f\n\x04Node\x12\x36\n\x07Getinfo\x12\x13.cln.GetinfoRequest\x1a\x14.cln.GetinfoResponse\"\x00\x12<\n\tListPeers\x12\x15.cln.ListpeersRequest\x1a\x16.cln.ListpeersResponse\"\x00\x12<\n\tListFunds\x12\x15.cln.ListfundsRequest\x1a\x16.cln.ListfundsResponse\"\x00\x12\x36\n\x07SendPay\x12\x13.cln.SendpayRequest\x1a\x14.cln.SendpayResponse\"\x00\x12\x45\n\x0cListChannels\x12\x18.cln.ListchannelsRequest\x1a\x19.cln.ListchannelsResponse\"\x00\x12<\n\tAddGossip\x12\x15.cln.AddgossipRequest\x1a\x16.cln.AddgossipResponse\"\x00\x12Q\n\x10\x41utoCleanInvoice\x12\x1c.cln.AutocleaninvoiceRequest\x1a\x1d.cln.AutocleaninvoiceResponse\"\x00\x12\x45\n\x0c\x43heckMessage\x12\x18.cln.CheckmessageRequest\x1a\x19.cln.CheckmessageResponse\"\x00\x12\x30\n\x05\x43lose\x12\x11.cln.CloseRequest\x1a\x12.cln.CloseResponse\"\x00\x12:\n\x0b\x43onnectPeer\x12\x13.cln.ConnectRequest\x1a\x14.cln.ConnectResponse\"\x00\x12H\n\rCreateInvoice\x12\x19.cln.CreateinvoiceRequest\x1a\x1a.cln.CreateinvoiceResponse\"\x00\x12<\n\tDatastore\x12\x15.cln.DatastoreRequest\x1a\x16.cln.DatastoreResponse\"\x00\x12K\n\x0e\x44\x61tastoreUsage\x12\x1a.cln.DatastoreusageRequest\x1a\x1b.cln.DatastoreusageResponse\"\x00\x12\x42\n\x0b\x43reateOnion\x12\x17.cln.CreateonionRequest\x1a\x18.cln.CreateonionResponse\"\x00\x12\x45\n\x0c\x44\x65lDatastore\x12\x18.cln.DeldatastoreRequest\x1a\x19.cln.DeldatastoreResponse\"\x00\x12T\n\x11\x44\x65lExpiredInvoice\x12\x1d.cln.DelexpiredinvoiceRequest\x1a\x1e.cln.DelexpiredinvoiceResponse\"\x00\x12?\n\nDelInvoice\x12\x16.cln.DelinvoiceRequest\x1a\x17.cln.DelinvoiceResponse\"\x00\x12\x36\n\x07Invoice\x12\x13.cln.InvoiceRequest\x1a\x14.cln.InvoiceResponse\"\x00\x12H\n\rListDatastore\x12\x19.cln.ListdatastoreRequest\x1a\x1a.cln.ListdatastoreResponse\"\x00\x12\x45\n\x0cListInvoices\x12\x18.cln.ListinvoicesRequest\x1a\x19.cln.ListinvoicesResponse\"\x00\x12<\n\tSendOnion\x12\x15.cln.SendonionRequest\x1a\x16.cln.SendonionResponse\"\x00\x12\x45\n\x0cListSendPays\x12\x18.cln.ListsendpaysRequest\x1a\x19.cln.ListsendpaysResponse\"\x00\x12Q\n\x10ListTransactions\x12\x1c.cln.ListtransactionsRequest\x1a\x1d.cln.ListtransactionsResponse\"\x00\x12*\n\x03Pay\x12\x0f.cln.PayRequest\x1a\x10.cln.PayResponse\"\x00\x12<\n\tListNodes\x12\x15.cln.ListnodesRequest\x1a\x16.cln.ListnodesResponse\"\x00\x12K\n\x0eWaitAnyInvoice\x12\x1a.cln.WaitanyinvoiceRequest\x1a\x1b.cln.WaitanyinvoiceResponse\"\x00\x12\x42\n\x0bWaitInvoice\x12\x17.cln.WaitinvoiceRequest\x1a\x18.cln.WaitinvoiceResponse\"\x00\x12\x42\n\x0bWaitSendPay\x12\x17.cln.WaitsendpayRequest\x1a\x18.cln.WaitsendpayResponse\"\x00\x12\x36\n\x07NewAddr\x12\x13.cln.NewaddrRequest\x1a\x14.cln.NewaddrResponse\"\x00\x12\x39\n\x08Withdraw\x12\x14.cln.WithdrawRequest\x1a\x15.cln.WithdrawResponse\"\x00\x12\x36\n\x07KeySend\x12\x13.cln.KeysendRequest\x1a\x14.cln.KeysendResponse\"\x00\x12\x39\n\x08\x46undPsbt\x12\x14.cln.FundpsbtRequest\x1a\x15.cln.FundpsbtResponse\"\x00\x12\x39\n\x08SendPsbt\x12\x14.cln.SendpsbtRequest\x1a\x15.cln.SendpsbtResponse\"\x00\x12\x39\n\x08SignPsbt\x12\x14.cln.SignpsbtRequest\x1a\x15.cln.SignpsbtResponse\"\x00\x12\x39\n\x08UtxoPsbt\x12\x14.cln.UtxopsbtRequest\x1a\x15.cln.UtxopsbtResponse\"\x00\x12<\n\tTxDiscard\x12\x15.cln.TxdiscardRequest\x1a\x16.cln.TxdiscardResponse\"\x00\x12<\n\tTxPrepare\x12\x15.cln.TxprepareRequest\x1a\x16.cln.TxprepareResponse\"\x00\x12\x33\n\x06TxSend\x12\x12.cln.TxsendRequest\x1a\x13.cln.TxsendResponse\"\x00\x12Q\n\x10ListPeerChannels\x12\x1c.cln.ListpeerchannelsRequest\x1a\x1d.cln.ListpeerchannelsResponse\"\x00\x12W\n\x12ListClosedChannels\x12\x1e.cln.ListclosedchannelsRequest\x1a\x1f.cln.ListclosedchannelsResponse\"\x00\x12<\n\tDecodePay\x12\x15.cln.DecodepayRequest\x1a\x16.cln.DecodepayResponse\"\x00\x12\x33\n\x06\x44\x65\x63ode\x12\x12.cln.DecodeRequest\x1a\x13.cln.DecodeResponse\"\x00\x12?\n\nDisconnect\x12\x16.cln.DisconnectRequest\x1a\x17.cln.DisconnectResponse\"\x00\x12\x39\n\x08\x46\x65\x65rates\x12\x14.cln.FeeratesRequest\x1a\x15.cln.FeeratesResponse\"\x00\x12\x45\n\x0c\x46\x65tchInvoice\x12\x18.cln.FetchinvoiceRequest\x1a\x19.cln.FetchinvoiceResponse\"\x00\x12\x42\n\x0b\x46undChannel\x12\x17.cln.FundchannelRequest\x1a\x18.cln.FundchannelResponse\"\x00\x12\x39\n\x08GetRoute\x12\x14.cln.GetrouteRequest\x1a\x15.cln.GetrouteResponse\"\x00\x12\x45\n\x0cListForwards\x12\x18.cln.ListforwardsRequest\x1a\x19.cln.ListforwardsResponse\"\x00\x12\x39\n\x08ListPays\x12\x14.cln.ListpaysRequest\x1a\x15.cln.ListpaysResponse\"\x00\x12<\n\tListHtlcs\x12\x15.cln.ListhtlcsRequest\x1a\x16.cln.ListhtlcsResponse\"\x00\x12-\n\x04Ping\x12\x10.cln.PingRequest\x1a\x11.cln.PingResponse\"\x00\x12H\n\rSendCustomMsg\x12\x19.cln.SendcustommsgRequest\x1a\x1a.cln.SendcustommsgResponse\"\x00\x12?\n\nSetChannel\x12\x16.cln.SetchannelRequest\x1a\x17.cln.SetchannelResponse\"\x00\x12\x42\n\x0bSignInvoice\x12\x17.cln.SigninvoiceRequest\x1a\x18.cln.SigninvoiceResponse\"\x00\x12\x42\n\x0bSignMessage\x12\x17.cln.SignmessageRequest\x1a\x18.cln.SignmessageResponse\"\x00\x12N\n\x0fWaitBlockHeight\x12\x1b.cln.WaitblockheightRequest\x1a\x1c.cln.WaitblockheightResponse\"\x00\x12-\n\x04Wait\x12\x10.cln.WaitRequest\x1a\x11.cln.WaitResponse\"\x00\x12-\n\x04Stop\x12\x10.cln.StopRequest\x1a\x11.cln.StopResponse\"\x00\x12T\n\x11PreApproveKeysend\x12\x1d.cln.PreapprovekeysendRequest\x1a\x1e.cln.PreapprovekeysendResponse\"\x00\x12T\n\x11PreApproveInvoice\x12\x1d.cln.PreapproveinvoiceRequest\x1a\x1e.cln.PreapproveinvoiceResponse\"\x00\x12\x45\n\x0cStaticBackup\x12\x18.cln.StaticbackupRequest\x1a\x19.cln.StaticbackupResponse\"\x00\x62\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\nnode.proto\x12\x03\x63ln\x1a\x10primitives.proto\"\x10\n\x0eGetinfoRequest\"\xc1\x04\n\x0fGetinfoResponse\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x12\n\x05\x61lias\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\r\n\x05\x63olor\x18\x03 \x01(\x0c\x12\x11\n\tnum_peers\x18\x04 \x01(\r\x12\x1c\n\x14num_pending_channels\x18\x05 \x01(\r\x12\x1b\n\x13num_active_channels\x18\x06 \x01(\r\x12\x1d\n\x15num_inactive_channels\x18\x07 \x01(\r\x12\x0f\n\x07version\x18\x08 \x01(\t\x12\x15\n\rlightning_dir\x18\t \x01(\t\x12\x33\n\x0cour_features\x18\n \x01(\x0b\x32\x18.cln.GetinfoOur_featuresH\x01\x88\x01\x01\x12\x13\n\x0b\x62lockheight\x18\x0b \x01(\r\x12\x0f\n\x07network\x18\x0c \x01(\t\x12(\n\x13\x66\x65\x65s_collected_msat\x18\r \x01(\x0b\x32\x0b.cln.Amount\x12$\n\x07\x61\x64\x64ress\x18\x0e \x03(\x0b\x32\x13.cln.GetinfoAddress\x12$\n\x07\x62inding\x18\x0f \x03(\x0b\x32\x13.cln.GetinfoBinding\x12\"\n\x15warning_bitcoind_sync\x18\x10 \x01(\tH\x02\x88\x01\x01\x12$\n\x17warning_lightningd_sync\x18\x11 \x01(\tH\x03\x88\x01\x01\x42\x08\n\x06_aliasB\x0f\n\r_our_featuresB\x18\n\x16_warning_bitcoind_syncB\x1a\n\x18_warning_lightningd_sync\"S\n\x13GetinfoOur_features\x12\x0c\n\x04init\x18\x01 \x01(\x0c\x12\x0c\n\x04node\x18\x02 \x01(\x0c\x12\x0f\n\x07\x63hannel\x18\x03 \x01(\x0c\x12\x0f\n\x07invoice\x18\x04 \x01(\x0c\"\xc4\x01\n\x0eGetinfoAddress\x12\x39\n\titem_type\x18\x01 \x01(\x0e\x32&.cln.GetinfoAddress.GetinfoAddressType\x12\x0c\n\x04port\x18\x02 \x01(\r\x12\x14\n\x07\x61\x64\x64ress\x18\x03 \x01(\tH\x00\x88\x01\x01\"G\n\x12GetinfoAddressType\x12\x07\n\x03\x44NS\x10\x00\x12\x08\n\x04IPV4\x10\x01\x12\x08\n\x04IPV6\x10\x02\x12\t\n\x05TORV2\x10\x03\x12\t\n\x05TORV3\x10\x04\x42\n\n\x08_address\"\x8a\x02\n\x0eGetinfoBinding\x12\x39\n\titem_type\x18\x01 \x01(\x0e\x32&.cln.GetinfoBinding.GetinfoBindingType\x12\x14\n\x07\x61\x64\x64ress\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x11\n\x04port\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\x13\n\x06socket\x18\x04 \x01(\tH\x02\x88\x01\x01\"_\n\x12GetinfoBindingType\x12\x10\n\x0cLOCAL_SOCKET\x10\x00\x12\r\n\tWEBSOCKET\x10\x05\x12\x08\n\x04IPV4\x10\x01\x12\x08\n\x04IPV6\x10\x02\x12\t\n\x05TORV2\x10\x03\x12\t\n\x05TORV3\x10\x04\x42\n\n\x08_addressB\x07\n\x05_portB\t\n\x07_socket\"H\n\x10ListpeersRequest\x12\x0f\n\x02id\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x12\x12\n\x05level\x18\x02 \x01(\tH\x01\x88\x01\x01\x42\x05\n\x03_idB\x08\n\x06_level\"7\n\x11ListpeersResponse\x12\"\n\x05peers\x18\x01 \x03(\x0b\x32\x13.cln.ListpeersPeers\"\x8e\x02\n\x0eListpeersPeers\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x11\n\tconnected\x18\x02 \x01(\x08\x12\x19\n\x0cnum_channels\x18\x08 \x01(\rH\x00\x88\x01\x01\x12#\n\x03log\x18\x03 \x03(\x0b\x32\x16.cln.ListpeersPeersLog\x12-\n\x08\x63hannels\x18\x04 \x03(\x0b\x32\x1b.cln.ListpeersPeersChannels\x12\x0f\n\x07netaddr\x18\x05 \x03(\t\x12\x18\n\x0bremote_addr\x18\x07 \x01(\tH\x01\x88\x01\x01\x12\x15\n\x08\x66\x65\x61tures\x18\x06 \x01(\x0cH\x02\x88\x01\x01\x42\x0f\n\r_num_channelsB\x0e\n\x0c_remote_addrB\x0b\n\t_features\"\xfd\x02\n\x11ListpeersPeersLog\x12?\n\titem_type\x18\x01 \x01(\x0e\x32,.cln.ListpeersPeersLog.ListpeersPeersLogType\x12\x18\n\x0bnum_skipped\x18\x02 \x01(\rH\x00\x88\x01\x01\x12\x11\n\x04time\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x13\n\x06source\x18\x04 \x01(\tH\x02\x88\x01\x01\x12\x10\n\x03log\x18\x05 \x01(\tH\x03\x88\x01\x01\x12\x14\n\x07node_id\x18\x06 \x01(\x0cH\x04\x88\x01\x01\x12\x11\n\x04\x64\x61ta\x18\x07 \x01(\x0cH\x05\x88\x01\x01\"i\n\x15ListpeersPeersLogType\x12\x0b\n\x07SKIPPED\x10\x00\x12\n\n\x06\x42ROKEN\x10\x01\x12\x0b\n\x07UNUSUAL\x10\x02\x12\x08\n\x04INFO\x10\x03\x12\t\n\x05\x44\x45\x42UG\x10\x04\x12\t\n\x05IO_IN\x10\x05\x12\n\n\x06IO_OUT\x10\x06\x42\x0e\n\x0c_num_skippedB\x07\n\x05_timeB\t\n\x07_sourceB\x06\n\x04_logB\n\n\x08_node_idB\x07\n\x05_data\"\x95\x18\n\x16ListpeersPeersChannels\x12\x46\n\x05state\x18\x01 \x01(\x0e\x32\x37.cln.ListpeersPeersChannels.ListpeersPeersChannelsState\x12\x19\n\x0cscratch_txid\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12\x38\n\x07\x66\x65\x65rate\x18\x03 \x01(\x0b\x32\".cln.ListpeersPeersChannelsFeerateH\x01\x88\x01\x01\x12\x12\n\x05owner\x18\x04 \x01(\tH\x02\x88\x01\x01\x12\x1d\n\x10short_channel_id\x18\x05 \x01(\tH\x03\x88\x01\x01\x12\x17\n\nchannel_id\x18\x06 \x01(\x0cH\x04\x88\x01\x01\x12\x19\n\x0c\x66unding_txid\x18\x07 \x01(\x0cH\x05\x88\x01\x01\x12\x1b\n\x0e\x66unding_outnum\x18\x08 \x01(\rH\x06\x88\x01\x01\x12\x1c\n\x0finitial_feerate\x18\t \x01(\tH\x07\x88\x01\x01\x12\x19\n\x0clast_feerate\x18\n \x01(\tH\x08\x88\x01\x01\x12\x19\n\x0cnext_feerate\x18\x0b \x01(\tH\t\x88\x01\x01\x12\x1a\n\rnext_fee_step\x18\x0c \x01(\rH\n\x88\x01\x01\x12\x35\n\x08inflight\x18\r \x03(\x0b\x32#.cln.ListpeersPeersChannelsInflight\x12\x15\n\x08\x63lose_to\x18\x0e \x01(\x0cH\x0b\x88\x01\x01\x12\x14\n\x07private\x18\x0f \x01(\x08H\x0c\x88\x01\x01\x12 \n\x06opener\x18\x10 \x01(\x0e\x32\x10.cln.ChannelSide\x12%\n\x06\x63loser\x18\x11 \x01(\x0e\x32\x10.cln.ChannelSideH\r\x88\x01\x01\x12\x10\n\x08\x66\x65\x61tures\x18\x12 \x03(\t\x12\x38\n\x07\x66unding\x18\x13 \x01(\x0b\x32\".cln.ListpeersPeersChannelsFundingH\x0e\x88\x01\x01\x12$\n\nto_us_msat\x18\x14 \x01(\x0b\x32\x0b.cln.AmountH\x0f\x88\x01\x01\x12(\n\x0emin_to_us_msat\x18\x15 \x01(\x0b\x32\x0b.cln.AmountH\x10\x88\x01\x01\x12(\n\x0emax_to_us_msat\x18\x16 \x01(\x0b\x32\x0b.cln.AmountH\x11\x88\x01\x01\x12$\n\ntotal_msat\x18\x17 \x01(\x0b\x32\x0b.cln.AmountH\x12\x88\x01\x01\x12\'\n\rfee_base_msat\x18\x18 \x01(\x0b\x32\x0b.cln.AmountH\x13\x88\x01\x01\x12(\n\x1b\x66\x65\x65_proportional_millionths\x18\x19 \x01(\rH\x14\x88\x01\x01\x12)\n\x0f\x64ust_limit_msat\x18\x1a \x01(\x0b\x32\x0b.cln.AmountH\x15\x88\x01\x01\x12\x30\n\x16max_total_htlc_in_msat\x18\x1b \x01(\x0b\x32\x0b.cln.AmountH\x16\x88\x01\x01\x12,\n\x12their_reserve_msat\x18\x1c \x01(\x0b\x32\x0b.cln.AmountH\x17\x88\x01\x01\x12*\n\x10our_reserve_msat\x18\x1d \x01(\x0b\x32\x0b.cln.AmountH\x18\x88\x01\x01\x12(\n\x0espendable_msat\x18\x1e \x01(\x0b\x32\x0b.cln.AmountH\x19\x88\x01\x01\x12)\n\x0freceivable_msat\x18\x1f \x01(\x0b\x32\x0b.cln.AmountH\x1a\x88\x01\x01\x12.\n\x14minimum_htlc_in_msat\x18 \x01(\x0b\x32\x0b.cln.AmountH\x1b\x88\x01\x01\x12/\n\x15minimum_htlc_out_msat\x18\x30 \x01(\x0b\x32\x0b.cln.AmountH\x1c\x88\x01\x01\x12/\n\x15maximum_htlc_out_msat\x18\x31 \x01(\x0b\x32\x0b.cln.AmountH\x1d\x88\x01\x01\x12 \n\x13their_to_self_delay\x18! \x01(\rH\x1e\x88\x01\x01\x12\x1e\n\x11our_to_self_delay\x18\" \x01(\rH\x1f\x88\x01\x01\x12\x1f\n\x12max_accepted_htlcs\x18# \x01(\rH \x88\x01\x01\x12\x34\n\x05\x61lias\x18\x32 \x01(\x0b\x32 .cln.ListpeersPeersChannelsAliasH!\x88\x01\x01\x12\x0e\n\x06status\x18% \x03(\t\x12 \n\x13in_payments_offered\x18& \x01(\x04H\"\x88\x01\x01\x12)\n\x0fin_offered_msat\x18\' \x01(\x0b\x32\x0b.cln.AmountH#\x88\x01\x01\x12\"\n\x15in_payments_fulfilled\x18( \x01(\x04H$\x88\x01\x01\x12+\n\x11in_fulfilled_msat\x18) \x01(\x0b\x32\x0b.cln.AmountH%\x88\x01\x01\x12!\n\x14out_payments_offered\x18* \x01(\x04H&\x88\x01\x01\x12*\n\x10out_offered_msat\x18+ \x01(\x0b\x32\x0b.cln.AmountH\'\x88\x01\x01\x12#\n\x16out_payments_fulfilled\x18, \x01(\x04H(\x88\x01\x01\x12,\n\x12out_fulfilled_msat\x18- \x01(\x0b\x32\x0b.cln.AmountH)\x88\x01\x01\x12/\n\x05htlcs\x18. \x03(\x0b\x32 .cln.ListpeersPeersChannelsHtlcs\x12\x1a\n\rclose_to_addr\x18/ \x01(\tH*\x88\x01\x01\"\xe0\x02\n\x1bListpeersPeersChannelsState\x12\x0c\n\x08OPENINGD\x10\x00\x12\x1c\n\x18\x43HANNELD_AWAITING_LOCKIN\x10\x01\x12\x13\n\x0f\x43HANNELD_NORMAL\x10\x02\x12\x1a\n\x16\x43HANNELD_SHUTTING_DOWN\x10\x03\x12\x18\n\x14\x43LOSINGD_SIGEXCHANGE\x10\x04\x12\x15\n\x11\x43LOSINGD_COMPLETE\x10\x05\x12\x17\n\x13\x41WAITING_UNILATERAL\x10\x06\x12\x16\n\x12\x46UNDING_SPEND_SEEN\x10\x07\x12\x0b\n\x07ONCHAIN\x10\x08\x12\x17\n\x13\x44UALOPEND_OPEN_INIT\x10\t\x12\x1d\n\x19\x44UALOPEND_AWAITING_LOCKIN\x10\n\x12\x1c\n\x18\x44UALOPEND_OPEN_COMMITTED\x10\x0b\x12\x1f\n\x1b\x44UALOPEND_OPEN_COMMIT_READY\x10\x0c\x42\x0f\n\r_scratch_txidB\n\n\x08_feerateB\x08\n\x06_ownerB\x13\n\x11_short_channel_idB\r\n\x0b_channel_idB\x0f\n\r_funding_txidB\x11\n\x0f_funding_outnumB\x12\n\x10_initial_feerateB\x0f\n\r_last_feerateB\x0f\n\r_next_feerateB\x10\n\x0e_next_fee_stepB\x0b\n\t_close_toB\n\n\x08_privateB\t\n\x07_closerB\n\n\x08_fundingB\r\n\x0b_to_us_msatB\x11\n\x0f_min_to_us_msatB\x11\n\x0f_max_to_us_msatB\r\n\x0b_total_msatB\x10\n\x0e_fee_base_msatB\x1e\n\x1c_fee_proportional_millionthsB\x12\n\x10_dust_limit_msatB\x19\n\x17_max_total_htlc_in_msatB\x15\n\x13_their_reserve_msatB\x13\n\x11_our_reserve_msatB\x11\n\x0f_spendable_msatB\x12\n\x10_receivable_msatB\x17\n\x15_minimum_htlc_in_msatB\x18\n\x16_minimum_htlc_out_msatB\x18\n\x16_maximum_htlc_out_msatB\x16\n\x14_their_to_self_delayB\x14\n\x12_our_to_self_delayB\x15\n\x13_max_accepted_htlcsB\x08\n\x06_aliasB\x16\n\x14_in_payments_offeredB\x12\n\x10_in_offered_msatB\x18\n\x16_in_payments_fulfilledB\x14\n\x12_in_fulfilled_msatB\x17\n\x15_out_payments_offeredB\x13\n\x11_out_offered_msatB\x19\n\x17_out_payments_fulfilledB\x15\n\x13_out_fulfilled_msatB\x10\n\x0e_close_to_addr\"=\n\x1dListpeersPeersChannelsFeerate\x12\r\n\x05perkw\x18\x01 \x01(\r\x12\r\n\x05perkb\x18\x02 \x01(\r\"\xf3\x01\n\x1eListpeersPeersChannelsInflight\x12\x14\n\x0c\x66unding_txid\x18\x01 \x01(\x0c\x12\x16\n\x0e\x66unding_outnum\x18\x02 \x01(\r\x12\x0f\n\x07\x66\x65\x65rate\x18\x03 \x01(\t\x12\'\n\x12total_funding_msat\x18\x04 \x01(\x0b\x32\x0b.cln.Amount\x12%\n\x10our_funding_msat\x18\x05 \x01(\x0b\x32\x0b.cln.Amount\x12\x1a\n\rsplice_amount\x18\x07 \x01(\x12H\x00\x88\x01\x01\x12\x14\n\x0cscratch_txid\x18\x06 \x01(\x0c\x42\x10\n\x0e_splice_amount\"\x9b\x02\n\x1dListpeersPeersChannelsFunding\x12%\n\x0bpushed_msat\x18\x03 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12%\n\x10local_funds_msat\x18\x04 \x01(\x0b\x32\x0b.cln.Amount\x12&\n\x11remote_funds_msat\x18\x07 \x01(\x0b\x32\x0b.cln.Amount\x12\'\n\rfee_paid_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x01\x88\x01\x01\x12\'\n\rfee_rcvd_msat\x18\x06 \x01(\x0b\x32\x0b.cln.AmountH\x02\x88\x01\x01\x42\x0e\n\x0c_pushed_msatB\x10\n\x0e_fee_paid_msatB\x10\n\x0e_fee_rcvd_msat\"[\n\x1bListpeersPeersChannelsAlias\x12\x12\n\x05local\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06remote\x18\x02 \x01(\tH\x01\x88\x01\x01\x42\x08\n\x06_localB\t\n\x07_remote\"\xf1\x02\n\x1bListpeersPeersChannelsHtlcs\x12X\n\tdirection\x18\x01 \x01(\x0e\x32\x45.cln.ListpeersPeersChannelsHtlcs.ListpeersPeersChannelsHtlcsDirection\x12\n\n\x02id\x18\x02 \x01(\x04\x12 \n\x0b\x61mount_msat\x18\x03 \x01(\x0b\x32\x0b.cln.Amount\x12\x0e\n\x06\x65xpiry\x18\x04 \x01(\r\x12\x14\n\x0cpayment_hash\x18\x05 \x01(\x0c\x12\x1a\n\rlocal_trimmed\x18\x06 \x01(\x08H\x00\x88\x01\x01\x12\x13\n\x06status\x18\x07 \x01(\tH\x01\x88\x01\x01\x12\x1d\n\x05state\x18\x08 \x01(\x0e\x32\x0e.cln.HtlcState\"7\n$ListpeersPeersChannelsHtlcsDirection\x12\x06\n\x02IN\x10\x00\x12\x07\n\x03OUT\x10\x01\x42\x10\n\x0e_local_trimmedB\t\n\x07_status\"0\n\x10ListfundsRequest\x12\x12\n\x05spent\x18\x01 \x01(\x08H\x00\x88\x01\x01\x42\x08\n\x06_spent\"e\n\x11ListfundsResponse\x12&\n\x07outputs\x18\x01 \x03(\x0b\x32\x15.cln.ListfundsOutputs\x12(\n\x08\x63hannels\x18\x02 \x03(\x0b\x32\x16.cln.ListfundsChannels\"\x83\x03\n\x10ListfundsOutputs\x12\x0c\n\x04txid\x18\x01 \x01(\x0c\x12\x0e\n\x06output\x18\x02 \x01(\r\x12 \n\x0b\x61mount_msat\x18\x03 \x01(\x0b\x32\x0b.cln.Amount\x12\x14\n\x0cscriptpubkey\x18\x04 \x01(\x0c\x12\x14\n\x07\x61\x64\x64ress\x18\x05 \x01(\tH\x00\x88\x01\x01\x12\x19\n\x0credeemscript\x18\x06 \x01(\x0cH\x01\x88\x01\x01\x12<\n\x06status\x18\x07 \x01(\x0e\x32,.cln.ListfundsOutputs.ListfundsOutputsStatus\x12\x10\n\x08reserved\x18\t \x01(\x08\x12\x18\n\x0b\x62lockheight\x18\x08 \x01(\rH\x02\x88\x01\x01\"Q\n\x16ListfundsOutputsStatus\x12\x0f\n\x0bUNCONFIRMED\x10\x00\x12\r\n\tCONFIRMED\x10\x01\x12\t\n\x05SPENT\x10\x02\x12\x0c\n\x08IMMATURE\x10\x03\x42\n\n\x08_addressB\x0f\n\r_redeemscriptB\x0e\n\x0c_blockheight\"\xab\x02\n\x11ListfundsChannels\x12\x0f\n\x07peer_id\x18\x01 \x01(\x0c\x12$\n\x0four_amount_msat\x18\x02 \x01(\x0b\x32\x0b.cln.Amount\x12 \n\x0b\x61mount_msat\x18\x03 \x01(\x0b\x32\x0b.cln.Amount\x12\x14\n\x0c\x66unding_txid\x18\x04 \x01(\x0c\x12\x16\n\x0e\x66unding_output\x18\x05 \x01(\r\x12\x11\n\tconnected\x18\x06 \x01(\x08\x12 \n\x05state\x18\x07 \x01(\x0e\x32\x11.cln.ChannelState\x12\x17\n\nchannel_id\x18\t \x01(\x0cH\x00\x88\x01\x01\x12\x1d\n\x10short_channel_id\x18\x08 \x01(\tH\x01\x88\x01\x01\x42\r\n\x0b_channel_idB\x13\n\x11_short_channel_id\"\xdd\x02\n\x0eSendpayRequest\x12 \n\x05route\x18\x01 \x03(\x0b\x32\x11.cln.SendpayRoute\x12\x14\n\x0cpayment_hash\x18\x02 \x01(\x0c\x12\x12\n\x05label\x18\x03 \x01(\tH\x00\x88\x01\x01\x12%\n\x0b\x61mount_msat\x18\n \x01(\x0b\x32\x0b.cln.AmountH\x01\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x05 \x01(\tH\x02\x88\x01\x01\x12\x1b\n\x0epayment_secret\x18\x06 \x01(\x0cH\x03\x88\x01\x01\x12\x13\n\x06partid\x18\x07 \x01(\rH\x04\x88\x01\x01\x12\x1a\n\rlocalinvreqid\x18\x0b \x01(\x0cH\x05\x88\x01\x01\x12\x14\n\x07groupid\x18\t \x01(\x04H\x06\x88\x01\x01\x42\x08\n\x06_labelB\x0e\n\x0c_amount_msatB\t\n\x07_bolt11B\x11\n\x0f_payment_secretB\t\n\x07_partidB\x10\n\x0e_localinvreqidB\n\n\x08_groupid\"\xad\x05\n\x0fSendpayResponse\x12\x1a\n\rcreated_index\x18\x10 \x01(\x04H\x00\x88\x01\x01\x12\x1a\n\rupdated_index\x18\x11 \x01(\x04H\x01\x88\x01\x01\x12\n\n\x02id\x18\x01 \x01(\x04\x12\x14\n\x07groupid\x18\x02 \x01(\x04H\x02\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12\x32\n\x06status\x18\x04 \x01(\x0e\x32\".cln.SendpayResponse.SendpayStatus\x12%\n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x03\x88\x01\x01\x12\x18\n\x0b\x64\x65stination\x18\x06 \x01(\x0cH\x04\x88\x01\x01\x12\x12\n\ncreated_at\x18\x07 \x01(\x04\x12\x19\n\x0c\x63ompleted_at\x18\x0f \x01(\x04H\x05\x88\x01\x01\x12%\n\x10\x61mount_sent_msat\x18\x08 \x01(\x0b\x32\x0b.cln.Amount\x12\x12\n\x05label\x18\t \x01(\tH\x06\x88\x01\x01\x12\x13\n\x06partid\x18\n \x01(\x04H\x07\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x0b \x01(\tH\x08\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x0c \x01(\tH\t\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\r \x01(\x0cH\n\x88\x01\x01\x12\x14\n\x07message\x18\x0e \x01(\tH\x0b\x88\x01\x01\"*\n\rSendpayStatus\x12\x0b\n\x07PENDING\x10\x00\x12\x0c\n\x08\x43OMPLETE\x10\x01\x42\x10\n\x0e_created_indexB\x10\n\x0e_updated_indexB\n\n\x08_groupidB\x0e\n\x0c_amount_msatB\x0e\n\x0c_destinationB\x0f\n\r_completed_atB\x08\n\x06_labelB\t\n\x07_partidB\t\n\x07_bolt11B\t\n\x07_bolt12B\x13\n\x11_payment_preimageB\n\n\x08_message\"\\\n\x0cSendpayRoute\x12 \n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.Amount\x12\n\n\x02id\x18\x02 \x01(\x0c\x12\r\n\x05\x64\x65lay\x18\x03 \x01(\r\x12\x0f\n\x07\x63hannel\x18\x04 \x01(\t\"\x93\x01\n\x13ListchannelsRequest\x12\x1d\n\x10short_channel_id\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06source\x18\x02 \x01(\x0cH\x01\x88\x01\x01\x12\x18\n\x0b\x64\x65stination\x18\x03 \x01(\x0cH\x02\x88\x01\x01\x42\x13\n\x11_short_channel_idB\t\n\x07_sourceB\x0e\n\x0c_destination\"C\n\x14ListchannelsResponse\x12+\n\x08\x63hannels\x18\x01 \x03(\x0b\x32\x19.cln.ListchannelsChannels\"\xb3\x03\n\x14ListchannelsChannels\x12\x0e\n\x06source\x18\x01 \x01(\x0c\x12\x13\n\x0b\x64\x65stination\x18\x02 \x01(\x0c\x12\x18\n\x10short_channel_id\x18\x03 \x01(\t\x12\x11\n\tdirection\x18\x10 \x01(\r\x12\x0e\n\x06public\x18\x04 \x01(\x08\x12 \n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.Amount\x12\x15\n\rmessage_flags\x18\x06 \x01(\r\x12\x15\n\rchannel_flags\x18\x07 \x01(\r\x12\x0e\n\x06\x61\x63tive\x18\x08 \x01(\x08\x12\x13\n\x0blast_update\x18\t \x01(\r\x12\x1d\n\x15\x62\x61se_fee_millisatoshi\x18\n \x01(\r\x12\x19\n\x11\x66\x65\x65_per_millionth\x18\x0b \x01(\r\x12\r\n\x05\x64\x65lay\x18\x0c \x01(\r\x12&\n\x11htlc_minimum_msat\x18\r \x01(\x0b\x32\x0b.cln.Amount\x12+\n\x11htlc_maximum_msat\x18\x0e \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12\x10\n\x08\x66\x65\x61tures\x18\x0f \x01(\x0c\x42\x14\n\x12_htlc_maximum_msat\"#\n\x10\x41\x64\x64gossipRequest\x12\x0f\n\x07message\x18\x01 \x01(\x0c\"\x13\n\x11\x41\x64\x64gossipResponse\"o\n\x17\x41utocleaninvoiceRequest\x12\x17\n\nexpired_by\x18\x01 \x01(\x04H\x00\x88\x01\x01\x12\x1a\n\rcycle_seconds\x18\x02 \x01(\x04H\x01\x88\x01\x01\x42\r\n\x0b_expired_byB\x10\n\x0e_cycle_seconds\"\x81\x01\n\x18\x41utocleaninvoiceResponse\x12\x0f\n\x07\x65nabled\x18\x01 \x01(\x08\x12\x17\n\nexpired_by\x18\x02 \x01(\x04H\x00\x88\x01\x01\x12\x1a\n\rcycle_seconds\x18\x03 \x01(\x04H\x01\x88\x01\x01\x42\r\n\x0b_expired_byB\x10\n\x0e_cycle_seconds\"U\n\x13\x43heckmessageRequest\x12\x0f\n\x07message\x18\x01 \x01(\t\x12\r\n\x05zbase\x18\x02 \x01(\t\x12\x13\n\x06pubkey\x18\x03 \x01(\x0cH\x00\x88\x01\x01\x42\t\n\x07_pubkey\"8\n\x14\x43heckmessageResponse\x12\x10\n\x08verified\x18\x01 \x01(\x08\x12\x0e\n\x06pubkey\x18\x02 \x01(\x0c\"\xcb\x02\n\x0c\x43loseRequest\x12\n\n\x02id\x18\x01 \x01(\t\x12\x1e\n\x11unilateraltimeout\x18\x02 \x01(\rH\x00\x88\x01\x01\x12\x18\n\x0b\x64\x65stination\x18\x03 \x01(\tH\x01\x88\x01\x01\x12!\n\x14\x66\x65\x65_negotiation_step\x18\x04 \x01(\tH\x02\x88\x01\x01\x12)\n\rwrong_funding\x18\x05 \x01(\x0b\x32\r.cln.OutpointH\x03\x88\x01\x01\x12\x1f\n\x12\x66orce_lease_closed\x18\x06 \x01(\x08H\x04\x88\x01\x01\x12\x1e\n\x08\x66\x65\x65range\x18\x07 \x03(\x0b\x32\x0c.cln.FeerateB\x14\n\x12_unilateraltimeoutB\x0e\n\x0c_destinationB\x17\n\x15_fee_negotiation_stepB\x10\n\x0e_wrong_fundingB\x15\n\x13_force_lease_closed\"\xab\x01\n\rCloseResponse\x12/\n\titem_type\x18\x01 \x01(\x0e\x32\x1c.cln.CloseResponse.CloseType\x12\x0f\n\x02tx\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12\x11\n\x04txid\x18\x03 \x01(\x0cH\x01\x88\x01\x01\"5\n\tCloseType\x12\n\n\x06MUTUAL\x10\x00\x12\x0e\n\nUNILATERAL\x10\x01\x12\x0c\n\x08UNOPENED\x10\x02\x42\x05\n\x03_txB\x07\n\x05_txid\"T\n\x0e\x43onnectRequest\x12\n\n\x02id\x18\x01 \x01(\t\x12\x11\n\x04host\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x11\n\x04port\x18\x03 \x01(\rH\x01\x88\x01\x01\x42\x07\n\x05_hostB\x07\n\x05_port\"\xb4\x01\n\x0f\x43onnectResponse\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x10\n\x08\x66\x65\x61tures\x18\x02 \x01(\x0c\x12\x38\n\tdirection\x18\x03 \x01(\x0e\x32%.cln.ConnectResponse.ConnectDirection\x12$\n\x07\x61\x64\x64ress\x18\x04 \x01(\x0b\x32\x13.cln.ConnectAddress\"#\n\x10\x43onnectDirection\x12\x06\n\x02IN\x10\x00\x12\x07\n\x03OUT\x10\x01\"\xfb\x01\n\x0e\x43onnectAddress\x12\x39\n\titem_type\x18\x01 \x01(\x0e\x32&.cln.ConnectAddress.ConnectAddressType\x12\x13\n\x06socket\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x14\n\x07\x61\x64\x64ress\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x11\n\x04port\x18\x04 \x01(\rH\x02\x88\x01\x01\"P\n\x12\x43onnectAddressType\x12\x10\n\x0cLOCAL_SOCKET\x10\x00\x12\x08\n\x04IPV4\x10\x01\x12\x08\n\x04IPV6\x10\x02\x12\t\n\x05TORV2\x10\x03\x12\t\n\x05TORV3\x10\x04\x42\t\n\x07_socketB\n\n\x08_addressB\x07\n\x05_port\"J\n\x14\x43reateinvoiceRequest\x12\x11\n\tinvstring\x18\x01 \x01(\t\x12\r\n\x05label\x18\x02 \x01(\t\x12\x10\n\x08preimage\x18\x03 \x01(\x0c\"\xfe\x05\n\x15\x43reateinvoiceResponse\x12\r\n\x05label\x18\x01 \x01(\t\x12\x13\n\x06\x62olt11\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x04 \x01(\x0c\x12%\n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x02\x88\x01\x01\x12>\n\x06status\x18\x06 \x01(\x0e\x32..cln.CreateinvoiceResponse.CreateinvoiceStatus\x12\x13\n\x0b\x64\x65scription\x18\x07 \x01(\t\x12\x12\n\nexpires_at\x18\x08 \x01(\x04\x12\x1a\n\rcreated_index\x18\x10 \x01(\x04H\x03\x88\x01\x01\x12\x16\n\tpay_index\x18\t \x01(\x04H\x04\x88\x01\x01\x12.\n\x14\x61mount_received_msat\x18\n \x01(\x0b\x32\x0b.cln.AmountH\x05\x88\x01\x01\x12\x14\n\x07paid_at\x18\x0b \x01(\x04H\x06\x88\x01\x01\x12;\n\rpaid_outpoint\x18\x11 \x01(\x0b\x32\x1f.cln.CreateinvoicePaid_outpointH\x07\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\x0c \x01(\x0cH\x08\x88\x01\x01\x12\x1b\n\x0elocal_offer_id\x18\r \x01(\x0cH\t\x88\x01\x01\x12\x1e\n\x11invreq_payer_note\x18\x0f \x01(\tH\n\x88\x01\x01\"8\n\x13\x43reateinvoiceStatus\x12\x08\n\x04PAID\x10\x00\x12\x0b\n\x07\x45XPIRED\x10\x01\x12\n\n\x06UNPAID\x10\x02\x42\t\n\x07_bolt11B\t\n\x07_bolt12B\x0e\n\x0c_amount_msatB\x10\n\x0e_created_indexB\x0c\n\n_pay_indexB\x17\n\x15_amount_received_msatB\n\n\x08_paid_atB\x10\n\x0e_paid_outpointB\x13\n\x11_payment_preimageB\x11\n\x0f_local_offer_idB\x14\n\x12_invreq_payer_note\"X\n\x1a\x43reateinvoicePaid_outpoint\x12\x11\n\x04txid\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x12\x13\n\x06outnum\x18\x02 \x01(\rH\x01\x88\x01\x01\x42\x07\n\x05_txidB\t\n\x07_outnum\"\xb4\x02\n\x10\x44\x61tastoreRequest\x12\x0b\n\x03key\x18\x05 \x03(\t\x12\x13\n\x06string\x18\x06 \x01(\tH\x00\x88\x01\x01\x12\x10\n\x03hex\x18\x02 \x01(\x0cH\x01\x88\x01\x01\x12\x36\n\x04mode\x18\x03 \x01(\x0e\x32#.cln.DatastoreRequest.DatastoreModeH\x02\x88\x01\x01\x12\x17\n\ngeneration\x18\x04 \x01(\x04H\x03\x88\x01\x01\"p\n\rDatastoreMode\x12\x0f\n\x0bMUST_CREATE\x10\x00\x12\x10\n\x0cMUST_REPLACE\x10\x01\x12\x15\n\x11\x43REATE_OR_REPLACE\x10\x02\x12\x0f\n\x0bMUST_APPEND\x10\x03\x12\x14\n\x10\x43REATE_OR_APPEND\x10\x04\x42\t\n\x07_stringB\x06\n\x04_hexB\x07\n\x05_modeB\r\n\x0b_generation\"\x82\x01\n\x11\x44\x61tastoreResponse\x12\x0b\n\x03key\x18\x05 \x03(\t\x12\x17\n\ngeneration\x18\x02 \x01(\x04H\x00\x88\x01\x01\x12\x10\n\x03hex\x18\x03 \x01(\x0cH\x01\x88\x01\x01\x12\x13\n\x06string\x18\x04 \x01(\tH\x02\x88\x01\x01\x42\r\n\x0b_generationB\x06\n\x04_hexB\t\n\x07_string\"\x17\n\x15\x44\x61tastoreusageRequest\"k\n\x16\x44\x61tastoreusageResponse\x12>\n\x0e\x64\x61tastoreusage\x18\x01 \x01(\x0b\x32!.cln.DatastoreusageDatastoreusageH\x00\x88\x01\x01\x42\x11\n\x0f_datastoreusage\"b\n\x1c\x44\x61tastoreusageDatastoreusage\x12\x10\n\x03key\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x18\n\x0btotal_bytes\x18\x02 \x01(\x04H\x01\x88\x01\x01\x42\x06\n\x04_keyB\x0e\n\x0c_total_bytes\"\x9d\x01\n\x12\x43reateonionRequest\x12\"\n\x04hops\x18\x01 \x03(\x0b\x32\x14.cln.CreateonionHops\x12\x11\n\tassocdata\x18\x02 \x01(\x0c\x12\x18\n\x0bsession_key\x18\x03 \x01(\x0cH\x00\x88\x01\x01\x12\x17\n\nonion_size\x18\x04 \x01(\rH\x01\x88\x01\x01\x42\x0e\n\x0c_session_keyB\r\n\x0b_onion_size\"<\n\x13\x43reateonionResponse\x12\r\n\x05onion\x18\x01 \x01(\x0c\x12\x16\n\x0eshared_secrets\x18\x02 \x03(\x0c\"2\n\x0f\x43reateonionHops\x12\x0e\n\x06pubkey\x18\x01 \x01(\x0c\x12\x0f\n\x07payload\x18\x02 \x01(\x0c\"J\n\x13\x44\x65ldatastoreRequest\x12\x0b\n\x03key\x18\x03 \x03(\t\x12\x17\n\ngeneration\x18\x02 \x01(\x04H\x00\x88\x01\x01\x42\r\n\x0b_generation\"\x85\x01\n\x14\x44\x65ldatastoreResponse\x12\x0b\n\x03key\x18\x05 \x03(\t\x12\x17\n\ngeneration\x18\x02 \x01(\x04H\x00\x88\x01\x01\x12\x10\n\x03hex\x18\x03 \x01(\x0cH\x01\x88\x01\x01\x12\x13\n\x06string\x18\x04 \x01(\tH\x02\x88\x01\x01\x42\r\n\x0b_generationB\x06\n\x04_hexB\t\n\x07_string\"H\n\x18\x44\x65lexpiredinvoiceRequest\x12\x1a\n\rmaxexpirytime\x18\x01 \x01(\x04H\x00\x88\x01\x01\x42\x10\n\x0e_maxexpirytime\"\x1b\n\x19\x44\x65lexpiredinvoiceResponse\"\xb6\x01\n\x11\x44\x65linvoiceRequest\x12\r\n\x05label\x18\x01 \x01(\t\x12\x37\n\x06status\x18\x02 \x01(\x0e\x32\'.cln.DelinvoiceRequest.DelinvoiceStatus\x12\x15\n\x08\x64\x65sconly\x18\x03 \x01(\x08H\x00\x88\x01\x01\"5\n\x10\x44\x65linvoiceStatus\x12\x08\n\x04PAID\x10\x00\x12\x0b\n\x07\x45XPIRED\x10\x01\x12\n\n\x06UNPAID\x10\x02\x42\x0b\n\t_desconly\"\xa1\x04\n\x12\x44\x65linvoiceResponse\x12\r\n\x05label\x18\x01 \x01(\t\x12\x13\n\x06\x62olt11\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x03 \x01(\tH\x01\x88\x01\x01\x12%\n\x0b\x61mount_msat\x18\x04 \x01(\x0b\x32\x0b.cln.AmountH\x02\x88\x01\x01\x12\x18\n\x0b\x64\x65scription\x18\x05 \x01(\tH\x03\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x06 \x01(\x0c\x12\x1a\n\rcreated_index\x18\x0c \x01(\x04H\x04\x88\x01\x01\x12\x1a\n\rupdated_index\x18\r \x01(\x04H\x05\x88\x01\x01\x12\x38\n\x06status\x18\x07 \x01(\x0e\x32(.cln.DelinvoiceResponse.DelinvoiceStatus\x12\x12\n\nexpires_at\x18\x08 \x01(\x04\x12\x1b\n\x0elocal_offer_id\x18\t \x01(\x0cH\x06\x88\x01\x01\x12\x1e\n\x11invreq_payer_note\x18\x0b \x01(\tH\x07\x88\x01\x01\"5\n\x10\x44\x65linvoiceStatus\x12\x08\n\x04PAID\x10\x00\x12\x0b\n\x07\x45XPIRED\x10\x01\x12\n\n\x06UNPAID\x10\x02\x42\t\n\x07_bolt11B\t\n\x07_bolt12B\x0e\n\x0c_amount_msatB\x0e\n\x0c_descriptionB\x10\n\x0e_created_indexB\x10\n\x0e_updated_indexB\x11\n\x0f_local_offer_idB\x14\n\x12_invreq_payer_note\"\xfa\x01\n\x0eInvoiceRequest\x12%\n\x0b\x61mount_msat\x18\n \x01(\x0b\x32\x10.cln.AmountOrAny\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\r\n\x05label\x18\x03 \x01(\t\x12\x13\n\x06\x65xpiry\x18\x07 \x01(\x04H\x00\x88\x01\x01\x12\x11\n\tfallbacks\x18\x04 \x03(\t\x12\x15\n\x08preimage\x18\x05 \x01(\x0cH\x01\x88\x01\x01\x12\x11\n\x04\x63ltv\x18\x06 \x01(\rH\x02\x88\x01\x01\x12\x19\n\x0c\x64\x65schashonly\x18\t \x01(\x08H\x03\x88\x01\x01\x42\t\n\x07_expiryB\x0b\n\t_preimageB\x07\n\x05_cltvB\x0f\n\r_deschashonly\"\x95\x03\n\x0fInvoiceResponse\x12\x0e\n\x06\x62olt11\x18\x01 \x01(\t\x12\x14\n\x0cpayment_hash\x18\x02 \x01(\x0c\x12\x16\n\x0epayment_secret\x18\x03 \x01(\x0c\x12\x12\n\nexpires_at\x18\x04 \x01(\x04\x12\x1a\n\rcreated_index\x18\n \x01(\x04H\x00\x88\x01\x01\x12\x1d\n\x10warning_capacity\x18\x05 \x01(\tH\x01\x88\x01\x01\x12\x1c\n\x0fwarning_offline\x18\x06 \x01(\tH\x02\x88\x01\x01\x12\x1d\n\x10warning_deadends\x18\x07 \x01(\tH\x03\x88\x01\x01\x12#\n\x16warning_private_unused\x18\x08 \x01(\tH\x04\x88\x01\x01\x12\x18\n\x0bwarning_mpp\x18\t \x01(\tH\x05\x88\x01\x01\x42\x10\n\x0e_created_indexB\x13\n\x11_warning_capacityB\x12\n\x10_warning_offlineB\x13\n\x11_warning_deadendsB\x19\n\x17_warning_private_unusedB\x0e\n\x0c_warning_mpp\"#\n\x14ListdatastoreRequest\x12\x0b\n\x03key\x18\x02 \x03(\t\"G\n\x15ListdatastoreResponse\x12.\n\tdatastore\x18\x01 \x03(\x0b\x32\x1b.cln.ListdatastoreDatastore\"\x87\x01\n\x16ListdatastoreDatastore\x12\x0b\n\x03key\x18\x01 \x03(\t\x12\x17\n\ngeneration\x18\x02 \x01(\x04H\x00\x88\x01\x01\x12\x10\n\x03hex\x18\x03 \x01(\x0cH\x01\x88\x01\x01\x12\x13\n\x06string\x18\x04 \x01(\tH\x02\x88\x01\x01\x42\r\n\x0b_generationB\x06\n\x04_hexB\t\n\x07_string\"\xde\x02\n\x13ListinvoicesRequest\x12\x12\n\x05label\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x16\n\tinvstring\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x19\n\x0cpayment_hash\x18\x03 \x01(\x0cH\x02\x88\x01\x01\x12\x15\n\x08offer_id\x18\x04 \x01(\tH\x03\x88\x01\x01\x12>\n\x05index\x18\x05 \x01(\x0e\x32*.cln.ListinvoicesRequest.ListinvoicesIndexH\x04\x88\x01\x01\x12\x12\n\x05start\x18\x06 \x01(\x04H\x05\x88\x01\x01\x12\x12\n\x05limit\x18\x07 \x01(\rH\x06\x88\x01\x01\"-\n\x11ListinvoicesIndex\x12\x0b\n\x07\x43REATED\x10\x00\x12\x0b\n\x07UPDATED\x10\x01\x42\x08\n\x06_labelB\x0c\n\n_invstringB\x0f\n\r_payment_hashB\x0b\n\t_offer_idB\x08\n\x06_indexB\x08\n\x06_startB\x08\n\x06_limit\"C\n\x14ListinvoicesResponse\x12+\n\x08invoices\x18\x01 \x03(\x0b\x32\x19.cln.ListinvoicesInvoices\"\xd4\x06\n\x14ListinvoicesInvoices\x12\r\n\x05label\x18\x01 \x01(\t\x12\x18\n\x0b\x64\x65scription\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12\x44\n\x06status\x18\x04 \x01(\x0e\x32\x34.cln.ListinvoicesInvoices.ListinvoicesInvoicesStatus\x12\x12\n\nexpires_at\x18\x05 \x01(\x04\x12%\n\x0b\x61mount_msat\x18\x06 \x01(\x0b\x32\x0b.cln.AmountH\x01\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x07 \x01(\tH\x02\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x08 \x01(\tH\x03\x88\x01\x01\x12\x1b\n\x0elocal_offer_id\x18\t \x01(\x0cH\x04\x88\x01\x01\x12\x1e\n\x11invreq_payer_note\x18\x0f \x01(\tH\x05\x88\x01\x01\x12\x1a\n\rcreated_index\x18\x10 \x01(\x04H\x06\x88\x01\x01\x12\x1a\n\rupdated_index\x18\x11 \x01(\x04H\x07\x88\x01\x01\x12\x16\n\tpay_index\x18\x0b \x01(\x04H\x08\x88\x01\x01\x12.\n\x14\x61mount_received_msat\x18\x0c \x01(\x0b\x32\x0b.cln.AmountH\t\x88\x01\x01\x12\x14\n\x07paid_at\x18\r \x01(\x04H\n\x88\x01\x01\x12\x42\n\rpaid_outpoint\x18\x12 \x01(\x0b\x32&.cln.ListinvoicesInvoicesPaid_outpointH\x0b\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\x0e \x01(\x0cH\x0c\x88\x01\x01\"?\n\x1aListinvoicesInvoicesStatus\x12\n\n\x06UNPAID\x10\x00\x12\x08\n\x04PAID\x10\x01\x12\x0b\n\x07\x45XPIRED\x10\x02\x42\x0e\n\x0c_descriptionB\x0e\n\x0c_amount_msatB\t\n\x07_bolt11B\t\n\x07_bolt12B\x11\n\x0f_local_offer_idB\x14\n\x12_invreq_payer_noteB\x10\n\x0e_created_indexB\x10\n\x0e_updated_indexB\x0c\n\n_pay_indexB\x17\n\x15_amount_received_msatB\n\n\x08_paid_atB\x10\n\x0e_paid_outpointB\x13\n\x11_payment_preimage\"_\n!ListinvoicesInvoicesPaid_outpoint\x12\x11\n\x04txid\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x12\x13\n\x06outnum\x18\x02 \x01(\rH\x01\x88\x01\x01\x42\x07\n\x05_txidB\t\n\x07_outnum\"\x8a\x03\n\x10SendonionRequest\x12\r\n\x05onion\x18\x01 \x01(\x0c\x12*\n\tfirst_hop\x18\x02 \x01(\x0b\x32\x17.cln.SendonionFirst_hop\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12\x12\n\x05label\x18\x04 \x01(\tH\x00\x88\x01\x01\x12\x16\n\x0eshared_secrets\x18\x05 \x03(\x0c\x12\x13\n\x06partid\x18\x06 \x01(\rH\x01\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x07 \x01(\tH\x02\x88\x01\x01\x12%\n\x0b\x61mount_msat\x18\x0c \x01(\x0b\x32\x0b.cln.AmountH\x03\x88\x01\x01\x12\x18\n\x0b\x64\x65stination\x18\t \x01(\x0cH\x04\x88\x01\x01\x12\x1a\n\rlocalinvreqid\x18\r \x01(\x0cH\x05\x88\x01\x01\x12\x14\n\x07groupid\x18\x0b \x01(\x04H\x06\x88\x01\x01\x42\x08\n\x06_labelB\t\n\x07_partidB\t\n\x07_bolt11B\x0e\n\x0c_amount_msatB\x0e\n\x0c_destinationB\x10\n\x0e_localinvreqidB\n\n\x08_groupid\"\xe7\x04\n\x11SendonionResponse\x12\x1a\n\rcreated_index\x18\x0e \x01(\x04H\x00\x88\x01\x01\x12\n\n\x02id\x18\x01 \x01(\x04\x12\x14\n\x0cpayment_hash\x18\x02 \x01(\x0c\x12\x36\n\x06status\x18\x03 \x01(\x0e\x32&.cln.SendonionResponse.SendonionStatus\x12%\n\x0b\x61mount_msat\x18\x04 \x01(\x0b\x32\x0b.cln.AmountH\x01\x88\x01\x01\x12\x18\n\x0b\x64\x65stination\x18\x05 \x01(\x0cH\x02\x88\x01\x01\x12\x12\n\ncreated_at\x18\x06 \x01(\x04\x12%\n\x10\x61mount_sent_msat\x18\x07 \x01(\x0b\x32\x0b.cln.Amount\x12\x12\n\x05label\x18\x08 \x01(\tH\x03\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\t \x01(\tH\x04\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\n \x01(\tH\x05\x88\x01\x01\x12\x13\n\x06partid\x18\r \x01(\x04H\x06\x88\x01\x01\x12\x1a\n\rupdated_index\x18\x0f \x01(\x04H\x07\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\x0b \x01(\x0cH\x08\x88\x01\x01\x12\x14\n\x07message\x18\x0c \x01(\tH\t\x88\x01\x01\",\n\x0fSendonionStatus\x12\x0b\n\x07PENDING\x10\x00\x12\x0c\n\x08\x43OMPLETE\x10\x01\x42\x10\n\x0e_created_indexB\x0e\n\x0c_amount_msatB\x0e\n\x0c_destinationB\x08\n\x06_labelB\t\n\x07_bolt11B\t\n\x07_bolt12B\t\n\x07_partidB\x10\n\x0e_updated_indexB\x13\n\x11_payment_preimageB\n\n\x08_message\"Q\n\x12SendonionFirst_hop\x12\n\n\x02id\x18\x01 \x01(\x0c\x12 \n\x0b\x61mount_msat\x18\x02 \x01(\x0b\x32\x0b.cln.Amount\x12\r\n\x05\x64\x65lay\x18\x03 \x01(\r\"\xa0\x03\n\x13ListsendpaysRequest\x12\x13\n\x06\x62olt11\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x19\n\x0cpayment_hash\x18\x02 \x01(\x0cH\x01\x88\x01\x01\x12@\n\x06status\x18\x03 \x01(\x0e\x32+.cln.ListsendpaysRequest.ListsendpaysStatusH\x02\x88\x01\x01\x12>\n\x05index\x18\x04 \x01(\x0e\x32*.cln.ListsendpaysRequest.ListsendpaysIndexH\x03\x88\x01\x01\x12\x12\n\x05start\x18\x05 \x01(\x04H\x04\x88\x01\x01\x12\x12\n\x05limit\x18\x06 \x01(\rH\x05\x88\x01\x01\";\n\x12ListsendpaysStatus\x12\x0b\n\x07PENDING\x10\x00\x12\x0c\n\x08\x43OMPLETE\x10\x01\x12\n\n\x06\x46\x41ILED\x10\x02\"-\n\x11ListsendpaysIndex\x12\x0b\n\x07\x43REATED\x10\x00\x12\x0b\n\x07UPDATED\x10\x01\x42\t\n\x07_bolt11B\x0f\n\r_payment_hashB\t\n\x07_statusB\x08\n\x06_indexB\x08\n\x06_startB\x08\n\x06_limit\"C\n\x14ListsendpaysResponse\x12+\n\x08payments\x18\x01 \x03(\x0b\x32\x19.cln.ListsendpaysPayments\"\xd0\x05\n\x14ListsendpaysPayments\x12\x1a\n\rcreated_index\x18\x10 \x01(\x04H\x00\x88\x01\x01\x12\n\n\x02id\x18\x01 \x01(\x04\x12\x0f\n\x07groupid\x18\x02 \x01(\x04\x12\x13\n\x06partid\x18\x0f \x01(\x04H\x01\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12\x1a\n\rupdated_index\x18\x11 \x01(\x04H\x02\x88\x01\x01\x12\x44\n\x06status\x18\x04 \x01(\x0e\x32\x34.cln.ListsendpaysPayments.ListsendpaysPaymentsStatus\x12%\n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x03\x88\x01\x01\x12\x18\n\x0b\x64\x65stination\x18\x06 \x01(\x0cH\x04\x88\x01\x01\x12\x12\n\ncreated_at\x18\x07 \x01(\x04\x12%\n\x10\x61mount_sent_msat\x18\x08 \x01(\x0b\x32\x0b.cln.Amount\x12\x12\n\x05label\x18\t \x01(\tH\x05\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\n \x01(\tH\x06\x88\x01\x01\x12\x18\n\x0b\x64\x65scription\x18\x0e \x01(\tH\x07\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x0b \x01(\tH\x08\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\x0c \x01(\x0cH\t\x88\x01\x01\x12\x17\n\nerroronion\x18\r \x01(\x0cH\n\x88\x01\x01\"C\n\x1aListsendpaysPaymentsStatus\x12\x0b\n\x07PENDING\x10\x00\x12\n\n\x06\x46\x41ILED\x10\x01\x12\x0c\n\x08\x43OMPLETE\x10\x02\x42\x10\n\x0e_created_indexB\t\n\x07_partidB\x10\n\x0e_updated_indexB\x0e\n\x0c_amount_msatB\x0e\n\x0c_destinationB\x08\n\x06_labelB\t\n\x07_bolt11B\x0e\n\x0c_descriptionB\t\n\x07_bolt12B\x13\n\x11_payment_preimageB\r\n\x0b_erroronion\"\x19\n\x17ListtransactionsRequest\"S\n\x18ListtransactionsResponse\x12\x37\n\x0ctransactions\x18\x01 \x03(\x0b\x32!.cln.ListtransactionsTransactions\"\xf8\x01\n\x1cListtransactionsTransactions\x12\x0c\n\x04hash\x18\x01 \x01(\x0c\x12\r\n\x05rawtx\x18\x02 \x01(\x0c\x12\x13\n\x0b\x62lockheight\x18\x03 \x01(\r\x12\x0f\n\x07txindex\x18\x04 \x01(\r\x12\x10\n\x08locktime\x18\x07 \x01(\r\x12\x0f\n\x07version\x18\x08 \x01(\r\x12\x37\n\x06inputs\x18\t \x03(\x0b\x32\'.cln.ListtransactionsTransactionsInputs\x12\x39\n\x07outputs\x18\n \x03(\x0b\x32(.cln.ListtransactionsTransactionsOutputs\"S\n\"ListtransactionsTransactionsInputs\x12\x0c\n\x04txid\x18\x01 \x01(\x0c\x12\r\n\x05index\x18\x02 \x01(\r\x12\x10\n\x08sequence\x18\x03 \x01(\r\"l\n#ListtransactionsTransactionsOutputs\x12\r\n\x05index\x18\x01 \x01(\r\x12 \n\x0b\x61mount_msat\x18\x06 \x01(\x0b\x32\x0b.cln.Amount\x12\x14\n\x0cscriptPubKey\x18\x03 \x01(\x0c\"\xda\x03\n\nPayRequest\x12\x0e\n\x06\x62olt11\x18\x01 \x01(\t\x12%\n\x0b\x61mount_msat\x18\r \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12\x12\n\x05label\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x17\n\nriskfactor\x18\x08 \x01(\x01H\x02\x88\x01\x01\x12\x1a\n\rmaxfeepercent\x18\x04 \x01(\x01H\x03\x88\x01\x01\x12\x16\n\tretry_for\x18\x05 \x01(\rH\x04\x88\x01\x01\x12\x15\n\x08maxdelay\x18\x06 \x01(\rH\x05\x88\x01\x01\x12#\n\texemptfee\x18\x07 \x01(\x0b\x32\x0b.cln.AmountH\x06\x88\x01\x01\x12\x1a\n\rlocalinvreqid\x18\x0e \x01(\x0cH\x07\x88\x01\x01\x12\x0f\n\x07\x65xclude\x18\n \x03(\t\x12 \n\x06maxfee\x18\x0b \x01(\x0b\x32\x0b.cln.AmountH\x08\x88\x01\x01\x12\x18\n\x0b\x64\x65scription\x18\x0c \x01(\tH\t\x88\x01\x01\x42\x0e\n\x0c_amount_msatB\x08\n\x06_labelB\r\n\x0b_riskfactorB\x10\n\x0e_maxfeepercentB\x0c\n\n_retry_forB\x0b\n\t_maxdelayB\x0c\n\n_exemptfeeB\x10\n\x0e_localinvreqidB\t\n\x07_maxfeeB\x0e\n\x0c_description\"\xfb\x02\n\x0bPayResponse\x12\x18\n\x10payment_preimage\x18\x01 \x01(\x0c\x12\x18\n\x0b\x64\x65stination\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12\x12\n\ncreated_at\x18\x04 \x01(\x01\x12\r\n\x05parts\x18\x05 \x01(\r\x12 \n\x0b\x61mount_msat\x18\x06 \x01(\x0b\x32\x0b.cln.Amount\x12%\n\x10\x61mount_sent_msat\x18\x07 \x01(\x0b\x32\x0b.cln.Amount\x12\'\n\x1awarning_partial_completion\x18\x08 \x01(\tH\x01\x88\x01\x01\x12*\n\x06status\x18\t \x01(\x0e\x32\x1a.cln.PayResponse.PayStatus\"2\n\tPayStatus\x12\x0c\n\x08\x43OMPLETE\x10\x00\x12\x0b\n\x07PENDING\x10\x01\x12\n\n\x06\x46\x41ILED\x10\x02\x42\x0e\n\x0c_destinationB\x1d\n\x1b_warning_partial_completion\"*\n\x10ListnodesRequest\x12\x0f\n\x02id\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x42\x05\n\x03_id\"7\n\x11ListnodesResponse\x12\"\n\x05nodes\x18\x01 \x03(\x0b\x32\x13.cln.ListnodesNodes\"\xe1\x01\n\x0eListnodesNodes\x12\x0e\n\x06nodeid\x18\x01 \x01(\x0c\x12\x1b\n\x0elast_timestamp\x18\x02 \x01(\rH\x00\x88\x01\x01\x12\x12\n\x05\x61lias\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x12\n\x05\x63olor\x18\x04 \x01(\x0cH\x02\x88\x01\x01\x12\x15\n\x08\x66\x65\x61tures\x18\x05 \x01(\x0cH\x03\x88\x01\x01\x12/\n\taddresses\x18\x06 \x03(\x0b\x32\x1c.cln.ListnodesNodesAddressesB\x11\n\x0f_last_timestampB\x08\n\x06_aliasB\x08\n\x06_colorB\x0b\n\t_features\"\xe8\x01\n\x17ListnodesNodesAddresses\x12K\n\titem_type\x18\x01 \x01(\x0e\x32\x38.cln.ListnodesNodesAddresses.ListnodesNodesAddressesType\x12\x0c\n\x04port\x18\x02 \x01(\r\x12\x14\n\x07\x61\x64\x64ress\x18\x03 \x01(\tH\x00\x88\x01\x01\"P\n\x1bListnodesNodesAddressesType\x12\x07\n\x03\x44NS\x10\x00\x12\x08\n\x04IPV4\x10\x01\x12\x08\n\x04IPV6\x10\x02\x12\t\n\x05TORV2\x10\x03\x12\t\n\x05TORV3\x10\x04\x42\n\n\x08_address\"g\n\x15WaitanyinvoiceRequest\x12\x1a\n\rlastpay_index\x18\x01 \x01(\x04H\x00\x88\x01\x01\x12\x14\n\x07timeout\x18\x02 \x01(\x04H\x01\x88\x01\x01\x42\x10\n\x0e_lastpay_indexB\n\n\x08_timeout\"\xbf\x05\n\x16WaitanyinvoiceResponse\x12\r\n\x05label\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12@\n\x06status\x18\x04 \x01(\x0e\x32\x30.cln.WaitanyinvoiceResponse.WaitanyinvoiceStatus\x12\x12\n\nexpires_at\x18\x05 \x01(\x04\x12%\n\x0b\x61mount_msat\x18\x06 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x07 \x01(\tH\x01\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x08 \x01(\tH\x02\x88\x01\x01\x12\x1a\n\rcreated_index\x18\r \x01(\x04H\x03\x88\x01\x01\x12\x1a\n\rupdated_index\x18\x0e \x01(\x04H\x04\x88\x01\x01\x12\x16\n\tpay_index\x18\t \x01(\x04H\x05\x88\x01\x01\x12.\n\x14\x61mount_received_msat\x18\n \x01(\x0b\x32\x0b.cln.AmountH\x06\x88\x01\x01\x12\x14\n\x07paid_at\x18\x0b \x01(\x04H\x07\x88\x01\x01\x12<\n\rpaid_outpoint\x18\x0f \x01(\x0b\x32 .cln.WaitanyinvoicePaid_outpointH\x08\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\x0c \x01(\x0cH\t\x88\x01\x01\"-\n\x14WaitanyinvoiceStatus\x12\x08\n\x04PAID\x10\x00\x12\x0b\n\x07\x45XPIRED\x10\x01\x42\x0e\n\x0c_amount_msatB\t\n\x07_bolt11B\t\n\x07_bolt12B\x10\n\x0e_created_indexB\x10\n\x0e_updated_indexB\x0c\n\n_pay_indexB\x17\n\x15_amount_received_msatB\n\n\x08_paid_atB\x10\n\x0e_paid_outpointB\x13\n\x11_payment_preimage\"Y\n\x1bWaitanyinvoicePaid_outpoint\x12\x11\n\x04txid\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x12\x13\n\x06outnum\x18\x02 \x01(\rH\x01\x88\x01\x01\x42\x07\n\x05_txidB\t\n\x07_outnum\"#\n\x12WaitinvoiceRequest\x12\r\n\x05label\x18\x01 \x01(\t\"\xb0\x05\n\x13WaitinvoiceResponse\x12\r\n\x05label\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12:\n\x06status\x18\x04 \x01(\x0e\x32*.cln.WaitinvoiceResponse.WaitinvoiceStatus\x12\x12\n\nexpires_at\x18\x05 \x01(\x04\x12%\n\x0b\x61mount_msat\x18\x06 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x07 \x01(\tH\x01\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x08 \x01(\tH\x02\x88\x01\x01\x12\x1a\n\rcreated_index\x18\r \x01(\x04H\x03\x88\x01\x01\x12\x1a\n\rupdated_index\x18\x0e \x01(\x04H\x04\x88\x01\x01\x12\x16\n\tpay_index\x18\t \x01(\x04H\x05\x88\x01\x01\x12.\n\x14\x61mount_received_msat\x18\n \x01(\x0b\x32\x0b.cln.AmountH\x06\x88\x01\x01\x12\x14\n\x07paid_at\x18\x0b \x01(\x04H\x07\x88\x01\x01\x12\x39\n\rpaid_outpoint\x18\x0f \x01(\x0b\x32\x1d.cln.WaitinvoicePaid_outpointH\x08\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\x0c \x01(\x0cH\t\x88\x01\x01\"*\n\x11WaitinvoiceStatus\x12\x08\n\x04PAID\x10\x00\x12\x0b\n\x07\x45XPIRED\x10\x01\x42\x0e\n\x0c_amount_msatB\t\n\x07_bolt11B\t\n\x07_bolt12B\x10\n\x0e_created_indexB\x10\n\x0e_updated_indexB\x0c\n\n_pay_indexB\x17\n\x15_amount_received_msatB\n\n\x08_paid_atB\x10\n\x0e_paid_outpointB\x13\n\x11_payment_preimage\"V\n\x18WaitinvoicePaid_outpoint\x12\x11\n\x04txid\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x12\x13\n\x06outnum\x18\x02 \x01(\rH\x01\x88\x01\x01\x42\x07\n\x05_txidB\t\n\x07_outnum\"\x8e\x01\n\x12WaitsendpayRequest\x12\x14\n\x0cpayment_hash\x18\x01 \x01(\x0c\x12\x14\n\x07timeout\x18\x03 \x01(\rH\x00\x88\x01\x01\x12\x13\n\x06partid\x18\x02 \x01(\x04H\x01\x88\x01\x01\x12\x14\n\x07groupid\x18\x04 \x01(\x04H\x02\x88\x01\x01\x42\n\n\x08_timeoutB\t\n\x07_partidB\n\n\x08_groupid\"\x8e\x05\n\x13WaitsendpayResponse\x12\x1a\n\rcreated_index\x18\x0f \x01(\x04H\x00\x88\x01\x01\x12\n\n\x02id\x18\x01 \x01(\x04\x12\x14\n\x07groupid\x18\x02 \x01(\x04H\x01\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12:\n\x06status\x18\x04 \x01(\x0e\x32*.cln.WaitsendpayResponse.WaitsendpayStatus\x12%\n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x02\x88\x01\x01\x12\x18\n\x0b\x64\x65stination\x18\x06 \x01(\x0cH\x03\x88\x01\x01\x12\x12\n\ncreated_at\x18\x07 \x01(\x04\x12\x1a\n\rupdated_index\x18\x10 \x01(\x04H\x04\x88\x01\x01\x12\x19\n\x0c\x63ompleted_at\x18\x0e \x01(\x01H\x05\x88\x01\x01\x12%\n\x10\x61mount_sent_msat\x18\x08 \x01(\x0b\x32\x0b.cln.Amount\x12\x12\n\x05label\x18\t \x01(\tH\x06\x88\x01\x01\x12\x13\n\x06partid\x18\n \x01(\x04H\x07\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x0b \x01(\tH\x08\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x0c \x01(\tH\t\x88\x01\x01\x12\x1d\n\x10payment_preimage\x18\r \x01(\x0cH\n\x88\x01\x01\"!\n\x11WaitsendpayStatus\x12\x0c\n\x08\x43OMPLETE\x10\x00\x42\x10\n\x0e_created_indexB\n\n\x08_groupidB\x0e\n\x0c_amount_msatB\x0e\n\x0c_destinationB\x10\n\x0e_updated_indexB\x0f\n\r_completed_atB\x08\n\x06_labelB\t\n\x07_partidB\t\n\x07_bolt11B\t\n\x07_bolt12B\x13\n\x11_payment_preimage\"\x97\x01\n\x0eNewaddrRequest\x12@\n\x0b\x61\x64\x64resstype\x18\x01 \x01(\x0e\x32&.cln.NewaddrRequest.NewaddrAddresstypeH\x00\x88\x01\x01\"3\n\x12NewaddrAddresstype\x12\n\n\x06\x42\x45\x43H32\x10\x00\x12\x08\n\x04P2TR\x10\x03\x12\x07\n\x03\x41LL\x10\x02\x42\x0e\n\x0c_addresstype\"M\n\x0fNewaddrResponse\x12\x11\n\x04p2tr\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06\x62\x65\x63h32\x18\x01 \x01(\tH\x01\x88\x01\x01\x42\x07\n\x05_p2trB\t\n\x07_bech32\"\xca\x01\n\x0fWithdrawRequest\x12\x13\n\x0b\x64\x65stination\x18\x01 \x01(\t\x12&\n\x07satoshi\x18\x02 \x01(\x0b\x32\x10.cln.AmountOrAllH\x00\x88\x01\x01\x12\"\n\x07\x66\x65\x65rate\x18\x05 \x01(\x0b\x32\x0c.cln.FeerateH\x01\x88\x01\x01\x12\x14\n\x07minconf\x18\x03 \x01(\rH\x02\x88\x01\x01\x12\x1c\n\x05utxos\x18\x04 \x03(\x0b\x32\r.cln.OutpointB\n\n\x08_satoshiB\n\n\x08_feerateB\n\n\x08_minconf\":\n\x10WithdrawResponse\x12\n\n\x02tx\x18\x01 \x01(\x0c\x12\x0c\n\x04txid\x18\x02 \x01(\x0c\x12\x0c\n\x04psbt\x18\x03 \x01(\t\"\x82\x03\n\x0eKeysendRequest\x12\x13\n\x0b\x64\x65stination\x18\x01 \x01(\x0c\x12 \n\x0b\x61mount_msat\x18\n \x01(\x0b\x32\x0b.cln.Amount\x12\x12\n\x05label\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x1a\n\rmaxfeepercent\x18\x04 \x01(\x01H\x01\x88\x01\x01\x12\x16\n\tretry_for\x18\x05 \x01(\rH\x02\x88\x01\x01\x12\x15\n\x08maxdelay\x18\x06 \x01(\rH\x03\x88\x01\x01\x12#\n\texemptfee\x18\x07 \x01(\x0b\x32\x0b.cln.AmountH\x04\x88\x01\x01\x12+\n\nroutehints\x18\x08 \x01(\x0b\x32\x12.cln.RoutehintListH\x05\x88\x01\x01\x12&\n\textratlvs\x18\t \x01(\x0b\x32\x0e.cln.TlvStreamH\x06\x88\x01\x01\x42\x08\n\x06_labelB\x10\n\x0e_maxfeepercentB\x0c\n\n_retry_forB\x0b\n\t_maxdelayB\x0c\n\n_exemptfeeB\r\n\x0b_routehintsB\x0c\n\n_extratlvs\"\xf2\x02\n\x0fKeysendResponse\x12\x18\n\x10payment_preimage\x18\x01 \x01(\x0c\x12\x18\n\x0b\x64\x65stination\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x03 \x01(\x0c\x12\x12\n\ncreated_at\x18\x04 \x01(\x01\x12\r\n\x05parts\x18\x05 \x01(\r\x12 \n\x0b\x61mount_msat\x18\x06 \x01(\x0b\x32\x0b.cln.Amount\x12%\n\x10\x61mount_sent_msat\x18\x07 \x01(\x0b\x32\x0b.cln.Amount\x12\'\n\x1awarning_partial_completion\x18\x08 \x01(\tH\x01\x88\x01\x01\x12\x32\n\x06status\x18\t \x01(\x0e\x32\".cln.KeysendResponse.KeysendStatus\"\x1d\n\rKeysendStatus\x12\x0c\n\x08\x43OMPLETE\x10\x00\x42\x0e\n\x0c_destinationB\x1d\n\x1b_warning_partial_completion\"\xa4\x03\n\x0f\x46undpsbtRequest\x12!\n\x07satoshi\x18\x01 \x01(\x0b\x32\x10.cln.AmountOrAll\x12\x1d\n\x07\x66\x65\x65rate\x18\x02 \x01(\x0b\x32\x0c.cln.Feerate\x12\x13\n\x0bstartweight\x18\x03 \x01(\r\x12\x14\n\x07minconf\x18\x04 \x01(\rH\x00\x88\x01\x01\x12\x14\n\x07reserve\x18\x05 \x01(\rH\x01\x88\x01\x01\x12\x15\n\x08locktime\x18\x06 \x01(\rH\x02\x88\x01\x01\x12\x1f\n\x12min_witness_weight\x18\x07 \x01(\rH\x03\x88\x01\x01\x12\x1d\n\x10\x65xcess_as_change\x18\x08 \x01(\x08H\x04\x88\x01\x01\x12\x17\n\nnonwrapped\x18\t \x01(\x08H\x05\x88\x01\x01\x12#\n\x16opening_anchor_channel\x18\n \x01(\x08H\x06\x88\x01\x01\x42\n\n\x08_minconfB\n\n\x08_reserveB\x0b\n\t_locktimeB\x15\n\x13_min_witness_weightB\x13\n\x11_excess_as_changeB\r\n\x0b_nonwrappedB\x19\n\x17_opening_anchor_channel\"\xd9\x01\n\x10\x46undpsbtResponse\x12\x0c\n\x04psbt\x18\x01 \x01(\t\x12\x16\n\x0e\x66\x65\x65rate_per_kw\x18\x02 \x01(\r\x12\x1e\n\x16\x65stimated_final_weight\x18\x03 \x01(\r\x12 \n\x0b\x65xcess_msat\x18\x04 \x01(\x0b\x32\x0b.cln.Amount\x12\x1a\n\rchange_outnum\x18\x05 \x01(\rH\x00\x88\x01\x01\x12/\n\x0creservations\x18\x06 \x03(\x0b\x32\x19.cln.FundpsbtReservationsB\x10\n\x0e_change_outnum\"u\n\x14\x46undpsbtReservations\x12\x0c\n\x04txid\x18\x01 \x01(\x0c\x12\x0c\n\x04vout\x18\x02 \x01(\r\x12\x14\n\x0cwas_reserved\x18\x03 \x01(\x08\x12\x10\n\x08reserved\x18\x04 \x01(\x08\x12\x19\n\x11reserved_to_block\x18\x05 \x01(\r\"A\n\x0fSendpsbtRequest\x12\x0c\n\x04psbt\x18\x01 \x01(\t\x12\x14\n\x07reserve\x18\x02 \x01(\x08H\x00\x88\x01\x01\x42\n\n\x08_reserve\",\n\x10SendpsbtResponse\x12\n\n\x02tx\x18\x01 \x01(\x0c\x12\x0c\n\x04txid\x18\x02 \x01(\x0c\"1\n\x0fSignpsbtRequest\x12\x0c\n\x04psbt\x18\x01 \x01(\t\x12\x10\n\x08signonly\x18\x02 \x03(\r\"\'\n\x10SignpsbtResponse\x12\x13\n\x0bsigned_psbt\x18\x01 \x01(\t\"\x9b\x03\n\x0fUtxopsbtRequest\x12\x1c\n\x07satoshi\x18\x01 \x01(\x0b\x32\x0b.cln.Amount\x12\x1d\n\x07\x66\x65\x65rate\x18\x02 \x01(\x0b\x32\x0c.cln.Feerate\x12\x13\n\x0bstartweight\x18\x03 \x01(\r\x12\x1c\n\x05utxos\x18\x04 \x03(\x0b\x32\r.cln.Outpoint\x12\x14\n\x07reserve\x18\x05 \x01(\rH\x00\x88\x01\x01\x12\x17\n\nreservedok\x18\x08 \x01(\x08H\x01\x88\x01\x01\x12\x15\n\x08locktime\x18\x06 \x01(\rH\x02\x88\x01\x01\x12\x1f\n\x12min_witness_weight\x18\x07 \x01(\rH\x03\x88\x01\x01\x12\x1d\n\x10\x65xcess_as_change\x18\t \x01(\x08H\x04\x88\x01\x01\x12#\n\x16opening_anchor_channel\x18\n \x01(\x08H\x05\x88\x01\x01\x42\n\n\x08_reserveB\r\n\x0b_reservedokB\x0b\n\t_locktimeB\x15\n\x13_min_witness_weightB\x13\n\x11_excess_as_changeB\x19\n\x17_opening_anchor_channel\"\xd9\x01\n\x10UtxopsbtResponse\x12\x0c\n\x04psbt\x18\x01 \x01(\t\x12\x16\n\x0e\x66\x65\x65rate_per_kw\x18\x02 \x01(\r\x12\x1e\n\x16\x65stimated_final_weight\x18\x03 \x01(\r\x12 \n\x0b\x65xcess_msat\x18\x04 \x01(\x0b\x32\x0b.cln.Amount\x12\x1a\n\rchange_outnum\x18\x05 \x01(\rH\x00\x88\x01\x01\x12/\n\x0creservations\x18\x06 \x03(\x0b\x32\x19.cln.UtxopsbtReservationsB\x10\n\x0e_change_outnum\"u\n\x14UtxopsbtReservations\x12\x0c\n\x04txid\x18\x01 \x01(\x0c\x12\x0c\n\x04vout\x18\x02 \x01(\r\x12\x14\n\x0cwas_reserved\x18\x03 \x01(\x08\x12\x10\n\x08reserved\x18\x04 \x01(\x08\x12\x19\n\x11reserved_to_block\x18\x05 \x01(\r\" \n\x10TxdiscardRequest\x12\x0c\n\x04txid\x18\x01 \x01(\x0c\"6\n\x11TxdiscardResponse\x12\x13\n\x0bunsigned_tx\x18\x01 \x01(\x0c\x12\x0c\n\x04txid\x18\x02 \x01(\x0c\"\xa4\x01\n\x10TxprepareRequest\x12 \n\x07outputs\x18\x05 \x03(\x0b\x32\x0f.cln.OutputDesc\x12\"\n\x07\x66\x65\x65rate\x18\x02 \x01(\x0b\x32\x0c.cln.FeerateH\x00\x88\x01\x01\x12\x14\n\x07minconf\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\x1c\n\x05utxos\x18\x04 \x03(\x0b\x32\r.cln.OutpointB\n\n\x08_feerateB\n\n\x08_minconf\"D\n\x11TxprepareResponse\x12\x0c\n\x04psbt\x18\x01 \x01(\t\x12\x13\n\x0bunsigned_tx\x18\x02 \x01(\x0c\x12\x0c\n\x04txid\x18\x03 \x01(\x0c\"\x1d\n\rTxsendRequest\x12\x0c\n\x04txid\x18\x01 \x01(\x0c\"8\n\x0eTxsendResponse\x12\x0c\n\x04psbt\x18\x01 \x01(\t\x12\n\n\x02tx\x18\x02 \x01(\x0c\x12\x0c\n\x04txid\x18\x03 \x01(\x0c\"1\n\x17ListpeerchannelsRequest\x12\x0f\n\x02id\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x42\x05\n\x03_id\"K\n\x18ListpeerchannelsResponse\x12/\n\x08\x63hannels\x18\x01 \x03(\x0b\x32\x1d.cln.ListpeerchannelsChannels\"\xe2\x1a\n\x18ListpeerchannelsChannels\x12\x14\n\x07peer_id\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x12\x1b\n\x0epeer_connected\x18\x02 \x01(\x08H\x01\x88\x01\x01\x12O\n\x05state\x18\x03 \x01(\x0e\x32;.cln.ListpeerchannelsChannels.ListpeerchannelsChannelsStateH\x02\x88\x01\x01\x12\x19\n\x0cscratch_txid\x18\x04 \x01(\x0cH\x03\x88\x01\x01\x12:\n\x07updates\x18\x37 \x01(\x0b\x32$.cln.ListpeerchannelsChannelsUpdatesH\x04\x88\x01\x01\x12\x1e\n\x11ignore_fee_limits\x18\x36 \x01(\x08H\x05\x88\x01\x01\x12:\n\x07\x66\x65\x65rate\x18\x06 \x01(\x0b\x32$.cln.ListpeerchannelsChannelsFeerateH\x06\x88\x01\x01\x12\x12\n\x05owner\x18\x07 \x01(\tH\x07\x88\x01\x01\x12\x1d\n\x10short_channel_id\x18\x08 \x01(\tH\x08\x88\x01\x01\x12\x17\n\nchannel_id\x18\t \x01(\x0cH\t\x88\x01\x01\x12\x19\n\x0c\x66unding_txid\x18\n \x01(\x0cH\n\x88\x01\x01\x12\x1b\n\x0e\x66unding_outnum\x18\x0b \x01(\rH\x0b\x88\x01\x01\x12\x1c\n\x0finitial_feerate\x18\x0c \x01(\tH\x0c\x88\x01\x01\x12\x19\n\x0clast_feerate\x18\r \x01(\tH\r\x88\x01\x01\x12\x19\n\x0cnext_feerate\x18\x0e \x01(\tH\x0e\x88\x01\x01\x12\x1a\n\rnext_fee_step\x18\x0f \x01(\rH\x0f\x88\x01\x01\x12\x37\n\x08inflight\x18\x10 \x03(\x0b\x32%.cln.ListpeerchannelsChannelsInflight\x12\x15\n\x08\x63lose_to\x18\x11 \x01(\x0cH\x10\x88\x01\x01\x12\x14\n\x07private\x18\x12 \x01(\x08H\x11\x88\x01\x01\x12%\n\x06opener\x18\x13 \x01(\x0e\x32\x10.cln.ChannelSideH\x12\x88\x01\x01\x12%\n\x06\x63loser\x18\x14 \x01(\x0e\x32\x10.cln.ChannelSideH\x13\x88\x01\x01\x12:\n\x07\x66unding\x18\x16 \x01(\x0b\x32$.cln.ListpeerchannelsChannelsFundingH\x14\x88\x01\x01\x12$\n\nto_us_msat\x18\x17 \x01(\x0b\x32\x0b.cln.AmountH\x15\x88\x01\x01\x12(\n\x0emin_to_us_msat\x18\x18 \x01(\x0b\x32\x0b.cln.AmountH\x16\x88\x01\x01\x12(\n\x0emax_to_us_msat\x18\x19 \x01(\x0b\x32\x0b.cln.AmountH\x17\x88\x01\x01\x12$\n\ntotal_msat\x18\x1a \x01(\x0b\x32\x0b.cln.AmountH\x18\x88\x01\x01\x12\'\n\rfee_base_msat\x18\x1b \x01(\x0b\x32\x0b.cln.AmountH\x19\x88\x01\x01\x12(\n\x1b\x66\x65\x65_proportional_millionths\x18\x1c \x01(\rH\x1a\x88\x01\x01\x12)\n\x0f\x64ust_limit_msat\x18\x1d \x01(\x0b\x32\x0b.cln.AmountH\x1b\x88\x01\x01\x12\x30\n\x16max_total_htlc_in_msat\x18\x1e \x01(\x0b\x32\x0b.cln.AmountH\x1c\x88\x01\x01\x12,\n\x12their_reserve_msat\x18\x1f \x01(\x0b\x32\x0b.cln.AmountH\x1d\x88\x01\x01\x12*\n\x10our_reserve_msat\x18 \x01(\x0b\x32\x0b.cln.AmountH\x1e\x88\x01\x01\x12(\n\x0espendable_msat\x18! \x01(\x0b\x32\x0b.cln.AmountH\x1f\x88\x01\x01\x12)\n\x0freceivable_msat\x18\" \x01(\x0b\x32\x0b.cln.AmountH \x88\x01\x01\x12.\n\x14minimum_htlc_in_msat\x18# \x01(\x0b\x32\x0b.cln.AmountH!\x88\x01\x01\x12/\n\x15minimum_htlc_out_msat\x18$ \x01(\x0b\x32\x0b.cln.AmountH\"\x88\x01\x01\x12/\n\x15maximum_htlc_out_msat\x18% \x01(\x0b\x32\x0b.cln.AmountH#\x88\x01\x01\x12 \n\x13their_to_self_delay\x18& \x01(\rH$\x88\x01\x01\x12\x1e\n\x11our_to_self_delay\x18\' \x01(\rH%\x88\x01\x01\x12\x1f\n\x12max_accepted_htlcs\x18( \x01(\rH&\x88\x01\x01\x12\x36\n\x05\x61lias\x18) \x01(\x0b\x32\".cln.ListpeerchannelsChannelsAliasH\'\x88\x01\x01\x12\x0e\n\x06status\x18+ \x03(\t\x12 \n\x13in_payments_offered\x18, \x01(\x04H(\x88\x01\x01\x12)\n\x0fin_offered_msat\x18- \x01(\x0b\x32\x0b.cln.AmountH)\x88\x01\x01\x12\"\n\x15in_payments_fulfilled\x18. \x01(\x04H*\x88\x01\x01\x12+\n\x11in_fulfilled_msat\x18/ \x01(\x0b\x32\x0b.cln.AmountH+\x88\x01\x01\x12!\n\x14out_payments_offered\x18\x30 \x01(\x04H,\x88\x01\x01\x12*\n\x10out_offered_msat\x18\x31 \x01(\x0b\x32\x0b.cln.AmountH-\x88\x01\x01\x12#\n\x16out_payments_fulfilled\x18\x32 \x01(\x04H.\x88\x01\x01\x12,\n\x12out_fulfilled_msat\x18\x33 \x01(\x0b\x32\x0b.cln.AmountH/\x88\x01\x01\x12#\n\x16last_stable_connection\x18\x38 \x01(\x04H0\x88\x01\x01\x12\x31\n\x05htlcs\x18\x34 \x03(\x0b\x32\".cln.ListpeerchannelsChannelsHtlcs\x12\x1a\n\rclose_to_addr\x18\x35 \x01(\tH1\x88\x01\x01\"\x80\x03\n\x1dListpeerchannelsChannelsState\x12\x0c\n\x08OPENINGD\x10\x00\x12\x1c\n\x18\x43HANNELD_AWAITING_LOCKIN\x10\x01\x12\x13\n\x0f\x43HANNELD_NORMAL\x10\x02\x12\x1a\n\x16\x43HANNELD_SHUTTING_DOWN\x10\x03\x12\x18\n\x14\x43LOSINGD_SIGEXCHANGE\x10\x04\x12\x15\n\x11\x43LOSINGD_COMPLETE\x10\x05\x12\x17\n\x13\x41WAITING_UNILATERAL\x10\x06\x12\x16\n\x12\x46UNDING_SPEND_SEEN\x10\x07\x12\x0b\n\x07ONCHAIN\x10\x08\x12\x17\n\x13\x44UALOPEND_OPEN_INIT\x10\t\x12\x1d\n\x19\x44UALOPEND_AWAITING_LOCKIN\x10\n\x12\x1c\n\x18\x43HANNELD_AWAITING_SPLICE\x10\x0b\x12\x1c\n\x18\x44UALOPEND_OPEN_COMMITTED\x10\x0c\x12\x1f\n\x1b\x44UALOPEND_OPEN_COMMIT_READY\x10\rB\n\n\x08_peer_idB\x11\n\x0f_peer_connectedB\x08\n\x06_stateB\x0f\n\r_scratch_txidB\n\n\x08_updatesB\x14\n\x12_ignore_fee_limitsB\n\n\x08_feerateB\x08\n\x06_ownerB\x13\n\x11_short_channel_idB\r\n\x0b_channel_idB\x0f\n\r_funding_txidB\x11\n\x0f_funding_outnumB\x12\n\x10_initial_feerateB\x0f\n\r_last_feerateB\x0f\n\r_next_feerateB\x10\n\x0e_next_fee_stepB\x0b\n\t_close_toB\n\n\x08_privateB\t\n\x07_openerB\t\n\x07_closerB\n\n\x08_fundingB\r\n\x0b_to_us_msatB\x11\n\x0f_min_to_us_msatB\x11\n\x0f_max_to_us_msatB\r\n\x0b_total_msatB\x10\n\x0e_fee_base_msatB\x1e\n\x1c_fee_proportional_millionthsB\x12\n\x10_dust_limit_msatB\x19\n\x17_max_total_htlc_in_msatB\x15\n\x13_their_reserve_msatB\x13\n\x11_our_reserve_msatB\x11\n\x0f_spendable_msatB\x12\n\x10_receivable_msatB\x17\n\x15_minimum_htlc_in_msatB\x18\n\x16_minimum_htlc_out_msatB\x18\n\x16_maximum_htlc_out_msatB\x16\n\x14_their_to_self_delayB\x14\n\x12_our_to_self_delayB\x15\n\x13_max_accepted_htlcsB\x08\n\x06_aliasB\x16\n\x14_in_payments_offeredB\x12\n\x10_in_offered_msatB\x18\n\x16_in_payments_fulfilledB\x14\n\x12_in_fulfilled_msatB\x17\n\x15_out_payments_offeredB\x13\n\x11_out_offered_msatB\x19\n\x17_out_payments_fulfilledB\x15\n\x13_out_fulfilled_msatB\x19\n\x17_last_stable_connectionB\x10\n\x0e_close_to_addr\"\xb6\x01\n\x1fListpeerchannelsChannelsUpdates\x12=\n\x05local\x18\x01 \x01(\x0b\x32).cln.ListpeerchannelsChannelsUpdatesLocalH\x00\x88\x01\x01\x12?\n\x06remote\x18\x02 \x01(\x0b\x32*.cln.ListpeerchannelsChannelsUpdatesRemoteH\x01\x88\x01\x01\x42\x08\n\x06_localB\t\n\x07_remote\"\xe7\x02\n$ListpeerchannelsChannelsUpdatesLocal\x12+\n\x11htlc_minimum_msat\x18\x01 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12+\n\x11htlc_maximum_msat\x18\x02 \x01(\x0b\x32\x0b.cln.AmountH\x01\x88\x01\x01\x12\x1e\n\x11\x63ltv_expiry_delta\x18\x03 \x01(\rH\x02\x88\x01\x01\x12\'\n\rfee_base_msat\x18\x04 \x01(\x0b\x32\x0b.cln.AmountH\x03\x88\x01\x01\x12(\n\x1b\x66\x65\x65_proportional_millionths\x18\x05 \x01(\rH\x04\x88\x01\x01\x42\x14\n\x12_htlc_minimum_msatB\x14\n\x12_htlc_maximum_msatB\x14\n\x12_cltv_expiry_deltaB\x10\n\x0e_fee_base_msatB\x1e\n\x1c_fee_proportional_millionths\"\xe8\x02\n%ListpeerchannelsChannelsUpdatesRemote\x12+\n\x11htlc_minimum_msat\x18\x01 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12+\n\x11htlc_maximum_msat\x18\x02 \x01(\x0b\x32\x0b.cln.AmountH\x01\x88\x01\x01\x12\x1e\n\x11\x63ltv_expiry_delta\x18\x03 \x01(\rH\x02\x88\x01\x01\x12\'\n\rfee_base_msat\x18\x04 \x01(\x0b\x32\x0b.cln.AmountH\x03\x88\x01\x01\x12(\n\x1b\x66\x65\x65_proportional_millionths\x18\x05 \x01(\rH\x04\x88\x01\x01\x42\x14\n\x12_htlc_minimum_msatB\x14\n\x12_htlc_maximum_msatB\x14\n\x12_cltv_expiry_deltaB\x10\n\x0e_fee_base_msatB\x1e\n\x1c_fee_proportional_millionths\"]\n\x1fListpeerchannelsChannelsFeerate\x12\x12\n\x05perkw\x18\x01 \x01(\rH\x00\x88\x01\x01\x12\x12\n\x05perkb\x18\x02 \x01(\rH\x01\x88\x01\x01\x42\x08\n\x06_perkwB\x08\n\x06_perkb\"\x80\x03\n ListpeerchannelsChannelsInflight\x12\x19\n\x0c\x66unding_txid\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x12\x1b\n\x0e\x66unding_outnum\x18\x02 \x01(\rH\x01\x88\x01\x01\x12\x14\n\x07\x66\x65\x65rate\x18\x03 \x01(\tH\x02\x88\x01\x01\x12,\n\x12total_funding_msat\x18\x04 \x01(\x0b\x32\x0b.cln.AmountH\x03\x88\x01\x01\x12\x1a\n\rsplice_amount\x18\x07 \x01(\x12H\x04\x88\x01\x01\x12*\n\x10our_funding_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x05\x88\x01\x01\x12\x19\n\x0cscratch_txid\x18\x06 \x01(\x0cH\x06\x88\x01\x01\x42\x0f\n\r_funding_txidB\x11\n\x0f_funding_outnumB\n\n\x08_feerateB\x15\n\x13_total_funding_msatB\x10\n\x0e_splice_amountB\x13\n\x11_our_funding_msatB\x0f\n\r_scratch_txid\"\xd2\x02\n\x1fListpeerchannelsChannelsFunding\x12%\n\x0bpushed_msat\x18\x01 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12*\n\x10local_funds_msat\x18\x02 \x01(\x0b\x32\x0b.cln.AmountH\x01\x88\x01\x01\x12+\n\x11remote_funds_msat\x18\x03 \x01(\x0b\x32\x0b.cln.AmountH\x02\x88\x01\x01\x12\'\n\rfee_paid_msat\x18\x04 \x01(\x0b\x32\x0b.cln.AmountH\x03\x88\x01\x01\x12\'\n\rfee_rcvd_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x04\x88\x01\x01\x42\x0e\n\x0c_pushed_msatB\x13\n\x11_local_funds_msatB\x14\n\x12_remote_funds_msatB\x10\n\x0e_fee_paid_msatB\x10\n\x0e_fee_rcvd_msat\"]\n\x1dListpeerchannelsChannelsAlias\x12\x12\n\x05local\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06remote\x18\x02 \x01(\tH\x01\x88\x01\x01\x42\x08\n\x06_localB\t\n\x07_remote\"\xe2\x03\n\x1dListpeerchannelsChannelsHtlcs\x12\x61\n\tdirection\x18\x01 \x01(\x0e\x32I.cln.ListpeerchannelsChannelsHtlcs.ListpeerchannelsChannelsHtlcsDirectionH\x00\x88\x01\x01\x12\x0f\n\x02id\x18\x02 \x01(\x04H\x01\x88\x01\x01\x12%\n\x0b\x61mount_msat\x18\x03 \x01(\x0b\x32\x0b.cln.AmountH\x02\x88\x01\x01\x12\x13\n\x06\x65xpiry\x18\x04 \x01(\rH\x03\x88\x01\x01\x12\x19\n\x0cpayment_hash\x18\x05 \x01(\x0cH\x04\x88\x01\x01\x12\x1a\n\rlocal_trimmed\x18\x06 \x01(\x08H\x05\x88\x01\x01\x12\x13\n\x06status\x18\x07 \x01(\tH\x06\x88\x01\x01\x12\"\n\x05state\x18\x08 \x01(\x0e\x32\x0e.cln.HtlcStateH\x07\x88\x01\x01\"9\n&ListpeerchannelsChannelsHtlcsDirection\x12\x06\n\x02IN\x10\x00\x12\x07\n\x03OUT\x10\x01\x42\x0c\n\n_directionB\x05\n\x03_idB\x0e\n\x0c_amount_msatB\t\n\x07_expiryB\x0f\n\r_payment_hashB\x10\n\x0e_local_trimmedB\t\n\x07_statusB\x08\n\x06_state\"3\n\x19ListclosedchannelsRequest\x12\x0f\n\x02id\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x42\x05\n\x03_id\"[\n\x1aListclosedchannelsResponse\x12=\n\x0e\x63losedchannels\x18\x01 \x03(\x0b\x32%.cln.ListclosedchannelsClosedchannels\"\xf2\t\n ListclosedchannelsClosedchannels\x12\x14\n\x07peer_id\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x12\x12\n\nchannel_id\x18\x02 \x01(\x0c\x12\x1d\n\x10short_channel_id\x18\x03 \x01(\tH\x01\x88\x01\x01\x12>\n\x05\x61lias\x18\x04 \x01(\x0b\x32*.cln.ListclosedchannelsClosedchannelsAliasH\x02\x88\x01\x01\x12 \n\x06opener\x18\x05 \x01(\x0e\x32\x10.cln.ChannelSide\x12%\n\x06\x63loser\x18\x06 \x01(\x0e\x32\x10.cln.ChannelSideH\x03\x88\x01\x01\x12\x0f\n\x07private\x18\x07 \x01(\x08\x12\x1f\n\x17total_local_commitments\x18\t \x01(\x04\x12 \n\x18total_remote_commitments\x18\n \x01(\x04\x12\x18\n\x10total_htlcs_sent\x18\x0b \x01(\x04\x12\x14\n\x0c\x66unding_txid\x18\x0c \x01(\x0c\x12\x16\n\x0e\x66unding_outnum\x18\r \x01(\r\x12\x0e\n\x06leased\x18\x0e \x01(\x08\x12/\n\x15\x66unding_fee_paid_msat\x18\x0f \x01(\x0b\x32\x0b.cln.AmountH\x04\x88\x01\x01\x12/\n\x15\x66unding_fee_rcvd_msat\x18\x10 \x01(\x0b\x32\x0b.cln.AmountH\x05\x88\x01\x01\x12-\n\x13\x66unding_pushed_msat\x18\x11 \x01(\x0b\x32\x0b.cln.AmountH\x06\x88\x01\x01\x12\x1f\n\ntotal_msat\x18\x12 \x01(\x0b\x32\x0b.cln.Amount\x12%\n\x10\x66inal_to_us_msat\x18\x13 \x01(\x0b\x32\x0b.cln.Amount\x12#\n\x0emin_to_us_msat\x18\x14 \x01(\x0b\x32\x0b.cln.Amount\x12#\n\x0emax_to_us_msat\x18\x15 \x01(\x0b\x32\x0b.cln.Amount\x12!\n\x14last_commitment_txid\x18\x16 \x01(\x0cH\x07\x88\x01\x01\x12\x32\n\x18last_commitment_fee_msat\x18\x17 \x01(\x0b\x32\x0b.cln.AmountH\x08\x88\x01\x01\x12\x66\n\x0b\x63lose_cause\x18\x18 \x01(\x0e\x32Q.cln.ListclosedchannelsClosedchannels.ListclosedchannelsClosedchannelsClose_cause\x12#\n\x16last_stable_connection\x18\x19 \x01(\x04H\t\x88\x01\x01\"v\n+ListclosedchannelsClosedchannelsClose_cause\x12\x0b\n\x07UNKNOWN\x10\x00\x12\t\n\x05LOCAL\x10\x01\x12\x08\n\x04USER\x10\x02\x12\n\n\x06REMOTE\x10\x03\x12\x0c\n\x08PROTOCOL\x10\x04\x12\x0b\n\x07ONCHAIN\x10\x05\x42\n\n\x08_peer_idB\x13\n\x11_short_channel_idB\x08\n\x06_aliasB\t\n\x07_closerB\x18\n\x16_funding_fee_paid_msatB\x18\n\x16_funding_fee_rcvd_msatB\x16\n\x14_funding_pushed_msatB\x17\n\x15_last_commitment_txidB\x1b\n\x19_last_commitment_fee_msatB\x19\n\x17_last_stable_connection\"e\n%ListclosedchannelsClosedchannelsAlias\x12\x12\n\x05local\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x13\n\x06remote\x18\x02 \x01(\tH\x01\x88\x01\x01\x42\x08\n\x06_localB\t\n\x07_remote\"L\n\x10\x44\x65\x63odepayRequest\x12\x0e\n\x06\x62olt11\x18\x01 \x01(\t\x12\x18\n\x0b\x64\x65scription\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_description\"\x8d\x04\n\x11\x44\x65\x63odepayResponse\x12\x10\n\x08\x63urrency\x18\x01 \x01(\t\x12\x12\n\ncreated_at\x18\x02 \x01(\x04\x12\x0e\n\x06\x65xpiry\x18\x03 \x01(\x04\x12\r\n\x05payee\x18\x04 \x01(\x0c\x12%\n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12\x14\n\x0cpayment_hash\x18\x06 \x01(\x0c\x12\x11\n\tsignature\x18\x07 \x01(\t\x12\x18\n\x0b\x64\x65scription\x18\x08 \x01(\tH\x01\x88\x01\x01\x12\x1d\n\x10\x64\x65scription_hash\x18\t \x01(\x0cH\x02\x88\x01\x01\x12\x1d\n\x15min_final_cltv_expiry\x18\n \x01(\r\x12\x1b\n\x0epayment_secret\x18\x0b \x01(\x0cH\x03\x88\x01\x01\x12\x15\n\x08\x66\x65\x61tures\x18\x0c \x01(\x0cH\x04\x88\x01\x01\x12\x1d\n\x10payment_metadata\x18\r \x01(\x0cH\x05\x88\x01\x01\x12*\n\tfallbacks\x18\x0e \x03(\x0b\x32\x17.cln.DecodepayFallbacks\x12\"\n\x05\x65xtra\x18\x10 \x03(\x0b\x32\x13.cln.DecodepayExtraB\x0e\n\x0c_amount_msatB\x0e\n\x0c_descriptionB\x13\n\x11_description_hashB\x11\n\x0f_payment_secretB\x0b\n\t_featuresB\x13\n\x11_payment_metadata\"\xd0\x01\n\x12\x44\x65\x63odepayFallbacks\x12\x41\n\titem_type\x18\x01 \x01(\x0e\x32..cln.DecodepayFallbacks.DecodepayFallbacksType\x12\x11\n\x04\x61\x64\x64r\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x0b\n\x03hex\x18\x03 \x01(\x0c\"N\n\x16\x44\x65\x63odepayFallbacksType\x12\t\n\x05P2PKH\x10\x00\x12\x08\n\x04P2SH\x10\x01\x12\n\n\x06P2WPKH\x10\x02\x12\t\n\x05P2WSH\x10\x03\x12\x08\n\x04P2TR\x10\x04\x42\x07\n\x05_addr\"+\n\x0e\x44\x65\x63odepayExtra\x12\x0b\n\x03tag\x18\x01 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\t\"\x1f\n\rDecodeRequest\x12\x0e\n\x06string\x18\x01 \x01(\t\"\xe8!\n\x0e\x44\x65\x63odeResponse\x12\x31\n\titem_type\x18\x01 \x01(\x0e\x32\x1e.cln.DecodeResponse.DecodeType\x12\r\n\x05valid\x18\x02 \x01(\x08\x12\x15\n\x08offer_id\x18\x03 \x01(\x0cH\x00\x88\x01\x01\x12\x14\n\x0coffer_chains\x18\x04 \x03(\x0c\x12\x1b\n\x0eoffer_metadata\x18\x05 \x01(\x0cH\x01\x88\x01\x01\x12\x1b\n\x0eoffer_currency\x18\x06 \x01(\tH\x02\x88\x01\x01\x12+\n\x1ewarning_unknown_offer_currency\x18\x07 \x01(\tH\x03\x88\x01\x01\x12 \n\x13\x63urrency_minor_unit\x18\x08 \x01(\rH\x04\x88\x01\x01\x12\x19\n\x0coffer_amount\x18\t \x01(\x04H\x05\x88\x01\x01\x12+\n\x11offer_amount_msat\x18\n \x01(\x0b\x32\x0b.cln.AmountH\x06\x88\x01\x01\x12\x1e\n\x11offer_description\x18\x0b \x01(\tH\x07\x88\x01\x01\x12\x19\n\x0coffer_issuer\x18\x0c \x01(\tH\x08\x88\x01\x01\x12\x1b\n\x0eoffer_features\x18\r \x01(\x0cH\t\x88\x01\x01\x12\"\n\x15offer_absolute_expiry\x18\x0e \x01(\x04H\n\x88\x01\x01\x12\x1f\n\x12offer_quantity_max\x18\x0f \x01(\x04H\x0b\x88\x01\x01\x12+\n\x0boffer_paths\x18\x10 \x03(\x0b\x32\x16.cln.DecodeOffer_paths\x12\x1a\n\roffer_node_id\x18\x11 \x01(\x0cH\x0c\x88\x01\x01\x12*\n\x1dwarning_missing_offer_node_id\x18\x14 \x01(\tH\r\x88\x01\x01\x12.\n!warning_invalid_offer_description\x18\x15 \x01(\tH\x0e\x88\x01\x01\x12.\n!warning_missing_offer_description\x18\x16 \x01(\tH\x0f\x88\x01\x01\x12+\n\x1ewarning_invalid_offer_currency\x18\x17 \x01(\tH\x10\x88\x01\x01\x12)\n\x1cwarning_invalid_offer_issuer\x18\x18 \x01(\tH\x11\x88\x01\x01\x12\x1c\n\x0finvreq_metadata\x18\x19 \x01(\x0cH\x12\x88\x01\x01\x12\x1c\n\x0finvreq_payer_id\x18\x1a \x01(\x0cH\x13\x88\x01\x01\x12\x19\n\x0cinvreq_chain\x18\x1b \x01(\x0cH\x14\x88\x01\x01\x12,\n\x12invreq_amount_msat\x18\x1c \x01(\x0b\x32\x0b.cln.AmountH\x15\x88\x01\x01\x12\x1c\n\x0finvreq_features\x18\x1d \x01(\x0cH\x16\x88\x01\x01\x12\x1c\n\x0finvreq_quantity\x18\x1e \x01(\x04H\x17\x88\x01\x01\x12\x1e\n\x11invreq_payer_note\x18\x1f \x01(\tH\x18\x88\x01\x01\x12&\n\x19invreq_recurrence_counter\x18 \x01(\rH\x19\x88\x01\x01\x12$\n\x17invreq_recurrence_start\x18! \x01(\rH\x1a\x88\x01\x01\x12,\n\x1fwarning_missing_invreq_metadata\x18# \x01(\tH\x1b\x88\x01\x01\x12,\n\x1fwarning_missing_invreq_payer_id\x18$ \x01(\tH\x1c\x88\x01\x01\x12.\n!warning_invalid_invreq_payer_note\x18% \x01(\tH\x1d\x88\x01\x01\x12\x36\n)warning_missing_invoice_request_signature\x18& \x01(\tH\x1e\x88\x01\x01\x12\x36\n)warning_invalid_invoice_request_signature\x18\' \x01(\tH\x1f\x88\x01\x01\x12\x1f\n\x12invoice_created_at\x18) \x01(\x04H \x88\x01\x01\x12$\n\x17invoice_relative_expiry\x18* \x01(\rH!\x88\x01\x01\x12!\n\x14invoice_payment_hash\x18+ \x01(\x0cH\"\x88\x01\x01\x12-\n\x13invoice_amount_msat\x18, \x01(\x0b\x32\x0b.cln.AmountH#\x88\x01\x01\x12\x37\n\x11invoice_fallbacks\x18- \x03(\x0b\x32\x1c.cln.DecodeInvoice_fallbacks\x12\x1d\n\x10invoice_features\x18. \x01(\x0cH$\x88\x01\x01\x12\x1c\n\x0finvoice_node_id\x18/ \x01(\x0cH%\x88\x01\x01\x12(\n\x1binvoice_recurrence_basetime\x18\x30 \x01(\x04H&\x88\x01\x01\x12*\n\x1dwarning_missing_invoice_paths\x18\x32 \x01(\tH\'\x88\x01\x01\x12/\n\"warning_missing_invoice_blindedpay\x18\x33 \x01(\tH(\x88\x01\x01\x12/\n\"warning_missing_invoice_created_at\x18\x34 \x01(\tH)\x88\x01\x01\x12\x31\n$warning_missing_invoice_payment_hash\x18\x35 \x01(\tH*\x88\x01\x01\x12+\n\x1ewarning_missing_invoice_amount\x18\x36 \x01(\tH+\x88\x01\x01\x12\x38\n+warning_missing_invoice_recurrence_basetime\x18\x37 \x01(\tH,\x88\x01\x01\x12,\n\x1fwarning_missing_invoice_node_id\x18\x38 \x01(\tH-\x88\x01\x01\x12.\n!warning_missing_invoice_signature\x18\x39 \x01(\tH.\x88\x01\x01\x12.\n!warning_invalid_invoice_signature\x18: \x01(\tH/\x88\x01\x01\x12\'\n\tfallbacks\x18; \x03(\x0b\x32\x14.cln.DecodeFallbacks\x12\x17\n\ncreated_at\x18< \x01(\x04H0\x88\x01\x01\x12\x13\n\x06\x65xpiry\x18= \x01(\x04H1\x88\x01\x01\x12\x12\n\x05payee\x18> \x01(\x0cH2\x88\x01\x01\x12\x19\n\x0cpayment_hash\x18? \x01(\x0cH3\x88\x01\x01\x12\x1d\n\x10\x64\x65scription_hash\x18@ \x01(\x0cH4\x88\x01\x01\x12\"\n\x15min_final_cltv_expiry\x18\x41 \x01(\rH5\x88\x01\x01\x12\x1b\n\x0epayment_secret\x18\x42 \x01(\x0cH6\x88\x01\x01\x12\x1d\n\x10payment_metadata\x18\x43 \x01(\x0cH7\x88\x01\x01\x12\x1f\n\x05\x65xtra\x18\x45 \x03(\x0b\x32\x10.cln.DecodeExtra\x12\x16\n\tunique_id\x18\x46 \x01(\tH8\x88\x01\x01\x12\x14\n\x07version\x18G \x01(\tH9\x88\x01\x01\x12\x13\n\x06string\x18H \x01(\tH:\x88\x01\x01\x12-\n\x0crestrictions\x18I \x03(\x0b\x32\x17.cln.DecodeRestrictions\x12&\n\x19warning_rune_invalid_utf8\x18J \x01(\tH;\x88\x01\x01\x12\x10\n\x03hex\x18K \x01(\x0cH<\x88\x01\x01\x12\x16\n\tdecrypted\x18L \x01(\x0cH=\x88\x01\x01\"\x83\x01\n\nDecodeType\x12\x10\n\x0c\x42OLT12_OFFER\x10\x00\x12\x12\n\x0e\x42OLT12_INVOICE\x10\x01\x12\x1a\n\x16\x42OLT12_INVOICE_REQUEST\x10\x02\x12\x12\n\x0e\x42OLT11_INVOICE\x10\x03\x12\x08\n\x04RUNE\x10\x04\x12\x15\n\x11\x45MERGENCY_RECOVER\x10\x05\x42\x0b\n\t_offer_idB\x11\n\x0f_offer_metadataB\x11\n\x0f_offer_currencyB!\n\x1f_warning_unknown_offer_currencyB\x16\n\x14_currency_minor_unitB\x0f\n\r_offer_amountB\x14\n\x12_offer_amount_msatB\x14\n\x12_offer_descriptionB\x0f\n\r_offer_issuerB\x11\n\x0f_offer_featuresB\x18\n\x16_offer_absolute_expiryB\x15\n\x13_offer_quantity_maxB\x10\n\x0e_offer_node_idB \n\x1e_warning_missing_offer_node_idB$\n\"_warning_invalid_offer_descriptionB$\n\"_warning_missing_offer_descriptionB!\n\x1f_warning_invalid_offer_currencyB\x1f\n\x1d_warning_invalid_offer_issuerB\x12\n\x10_invreq_metadataB\x12\n\x10_invreq_payer_idB\x0f\n\r_invreq_chainB\x15\n\x13_invreq_amount_msatB\x12\n\x10_invreq_featuresB\x12\n\x10_invreq_quantityB\x14\n\x12_invreq_payer_noteB\x1c\n\x1a_invreq_recurrence_counterB\x1a\n\x18_invreq_recurrence_startB\"\n _warning_missing_invreq_metadataB\"\n _warning_missing_invreq_payer_idB$\n\"_warning_invalid_invreq_payer_noteB,\n*_warning_missing_invoice_request_signatureB,\n*_warning_invalid_invoice_request_signatureB\x15\n\x13_invoice_created_atB\x1a\n\x18_invoice_relative_expiryB\x17\n\x15_invoice_payment_hashB\x16\n\x14_invoice_amount_msatB\x13\n\x11_invoice_featuresB\x12\n\x10_invoice_node_idB\x1e\n\x1c_invoice_recurrence_basetimeB \n\x1e_warning_missing_invoice_pathsB%\n#_warning_missing_invoice_blindedpayB%\n#_warning_missing_invoice_created_atB\'\n%_warning_missing_invoice_payment_hashB!\n\x1f_warning_missing_invoice_amountB.\n,_warning_missing_invoice_recurrence_basetimeB\"\n _warning_missing_invoice_node_idB$\n\"_warning_missing_invoice_signatureB$\n\"_warning_invalid_invoice_signatureB\r\n\x0b_created_atB\t\n\x07_expiryB\x08\n\x06_payeeB\x0f\n\r_payment_hashB\x13\n\x11_description_hashB\x18\n\x16_min_final_cltv_expiryB\x11\n\x0f_payment_secretB\x13\n\x11_payment_metadataB\x0c\n\n_unique_idB\n\n\x08_versionB\t\n\x07_stringB\x1c\n\x1a_warning_rune_invalid_utf8B\x06\n\x04_hexB\x0c\n\n_decrypted\"<\n\x11\x44\x65\x63odeOffer_paths\x12\x15\n\rfirst_node_id\x18\x01 \x01(\x0c\x12\x10\n\x08\x62linding\x18\x02 \x01(\x0c\"\x8a\x01\n\x1f\x44\x65\x63odeOffer_recurrencePaywindow\x12\x16\n\x0eseconds_before\x18\x01 \x01(\r\x12\x15\n\rseconds_after\x18\x02 \x01(\r\x12 \n\x13proportional_amount\x18\x03 \x01(\x08H\x00\x88\x01\x01\x42\x16\n\x14_proportional_amount\"T\n\x17\x44\x65\x63odeInvoice_pathsPath\x12\x17\n\x0f\x62linded_node_id\x18\x01 \x01(\x0c\x12 \n\x18\x65ncrypted_recipient_data\x18\x02 \x01(\x0c\"Y\n\x17\x44\x65\x63odeInvoice_fallbacks\x12\x0f\n\x07version\x18\x01 \x01(\r\x12\x0b\n\x03hex\x18\x02 \x01(\x0c\x12\x14\n\x07\x61\x64\x64ress\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\n\n\x08_address\"w\n\x0f\x44\x65\x63odeFallbacks\x12\x36\n)warning_invoice_fallbacks_version_invalid\x18\x01 \x01(\tH\x00\x88\x01\x01\x42,\n*_warning_invoice_fallbacks_version_invalid\"(\n\x0b\x44\x65\x63odeExtra\x12\x0b\n\x03tag\x18\x01 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\t\";\n\x12\x44\x65\x63odeRestrictions\x12\x14\n\x0c\x61lternatives\x18\x01 \x03(\t\x12\x0f\n\x07summary\x18\x02 \x01(\t\"=\n\x11\x44isconnectRequest\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x12\n\x05\x66orce\x18\x02 \x01(\x08H\x00\x88\x01\x01\x42\x08\n\x06_force\"\x14\n\x12\x44isconnectResponse\"k\n\x0f\x46\x65\x65ratesRequest\x12\x31\n\x05style\x18\x01 \x01(\x0e\x32\".cln.FeeratesRequest.FeeratesStyle\"%\n\rFeeratesStyle\x12\t\n\x05PERKB\x10\x00\x12\t\n\x05PERKW\x10\x01\"\x9c\x02\n\x10\x46\x65\x65ratesResponse\x12%\n\x18warning_missing_feerates\x18\x01 \x01(\tH\x00\x88\x01\x01\x12&\n\x05perkb\x18\x02 \x01(\x0b\x32\x12.cln.FeeratesPerkbH\x01\x88\x01\x01\x12&\n\x05perkw\x18\x03 \x01(\x0b\x32\x12.cln.FeeratesPerkwH\x02\x88\x01\x01\x12\x46\n\x15onchain_fee_estimates\x18\x04 \x01(\x0b\x32\".cln.FeeratesOnchain_fee_estimatesH\x03\x88\x01\x01\x42\x1b\n\x19_warning_missing_feeratesB\x08\n\x06_perkbB\x08\n\x06_perkwB\x18\n\x16_onchain_fee_estimates\"\xd3\x03\n\rFeeratesPerkb\x12\x16\n\x0emin_acceptable\x18\x01 \x01(\r\x12\x16\n\x0emax_acceptable\x18\x02 \x01(\r\x12\x12\n\x05\x66loor\x18\n \x01(\rH\x00\x88\x01\x01\x12.\n\testimates\x18\t \x03(\x0b\x32\x1b.cln.FeeratesPerkbEstimates\x12\x14\n\x07opening\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\x19\n\x0cmutual_close\x18\x04 \x01(\rH\x02\x88\x01\x01\x12\x1d\n\x10unilateral_close\x18\x05 \x01(\rH\x03\x88\x01\x01\x12$\n\x17unilateral_anchor_close\x18\x0b \x01(\rH\x04\x88\x01\x01\x12\x1a\n\rdelayed_to_us\x18\x06 \x01(\rH\x05\x88\x01\x01\x12\x1c\n\x0fhtlc_resolution\x18\x07 \x01(\rH\x06\x88\x01\x01\x12\x14\n\x07penalty\x18\x08 \x01(\rH\x07\x88\x01\x01\x42\x08\n\x06_floorB\n\n\x08_openingB\x0f\n\r_mutual_closeB\x13\n\x11_unilateral_closeB\x1a\n\x18_unilateral_anchor_closeB\x10\n\x0e_delayed_to_usB\x12\n\x10_htlc_resolutionB\n\n\x08_penalty\"\x96\x01\n\x16\x46\x65\x65ratesPerkbEstimates\x12\x17\n\nblockcount\x18\x01 \x01(\rH\x00\x88\x01\x01\x12\x14\n\x07\x66\x65\x65rate\x18\x02 \x01(\rH\x01\x88\x01\x01\x12\x1d\n\x10smoothed_feerate\x18\x03 \x01(\rH\x02\x88\x01\x01\x42\r\n\x0b_blockcountB\n\n\x08_feerateB\x13\n\x11_smoothed_feerate\"\xd3\x03\n\rFeeratesPerkw\x12\x16\n\x0emin_acceptable\x18\x01 \x01(\r\x12\x16\n\x0emax_acceptable\x18\x02 \x01(\r\x12\x12\n\x05\x66loor\x18\n \x01(\rH\x00\x88\x01\x01\x12.\n\testimates\x18\t \x03(\x0b\x32\x1b.cln.FeeratesPerkwEstimates\x12\x14\n\x07opening\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\x19\n\x0cmutual_close\x18\x04 \x01(\rH\x02\x88\x01\x01\x12\x1d\n\x10unilateral_close\x18\x05 \x01(\rH\x03\x88\x01\x01\x12$\n\x17unilateral_anchor_close\x18\x0b \x01(\rH\x04\x88\x01\x01\x12\x1a\n\rdelayed_to_us\x18\x06 \x01(\rH\x05\x88\x01\x01\x12\x1c\n\x0fhtlc_resolution\x18\x07 \x01(\rH\x06\x88\x01\x01\x12\x14\n\x07penalty\x18\x08 \x01(\rH\x07\x88\x01\x01\x42\x08\n\x06_floorB\n\n\x08_openingB\x0f\n\r_mutual_closeB\x13\n\x11_unilateral_closeB\x1a\n\x18_unilateral_anchor_closeB\x10\n\x0e_delayed_to_usB\x12\n\x10_htlc_resolutionB\n\n\x08_penalty\"\x96\x01\n\x16\x46\x65\x65ratesPerkwEstimates\x12\x17\n\nblockcount\x18\x01 \x01(\rH\x00\x88\x01\x01\x12\x14\n\x07\x66\x65\x65rate\x18\x02 \x01(\rH\x01\x88\x01\x01\x12\x1d\n\x10smoothed_feerate\x18\x03 \x01(\rH\x02\x88\x01\x01\x42\r\n\x0b_blockcountB\n\n\x08_feerateB\x13\n\x11_smoothed_feerate\"\x9b\x02\n\x1d\x46\x65\x65ratesOnchain_fee_estimates\x12 \n\x18opening_channel_satoshis\x18\x01 \x01(\x04\x12\x1d\n\x15mutual_close_satoshis\x18\x02 \x01(\x04\x12!\n\x19unilateral_close_satoshis\x18\x03 \x01(\x04\x12\x30\n#unilateral_close_nonanchor_satoshis\x18\x06 \x01(\x04H\x00\x88\x01\x01\x12\x1d\n\x15htlc_timeout_satoshis\x18\x04 \x01(\x04\x12\x1d\n\x15htlc_success_satoshis\x18\x05 \x01(\x04\x42&\n$_unilateral_close_nonanchor_satoshis\"\xe9\x02\n\x13\x46\x65tchinvoiceRequest\x12\r\n\x05offer\x18\x01 \x01(\t\x12%\n\x0b\x61mount_msat\x18\x02 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12\x15\n\x08quantity\x18\x03 \x01(\x04H\x01\x88\x01\x01\x12\x1f\n\x12recurrence_counter\x18\x04 \x01(\x04H\x02\x88\x01\x01\x12\x1d\n\x10recurrence_start\x18\x05 \x01(\x01H\x03\x88\x01\x01\x12\x1d\n\x10recurrence_label\x18\x06 \x01(\tH\x04\x88\x01\x01\x12\x14\n\x07timeout\x18\x07 \x01(\x01H\x05\x88\x01\x01\x12\x17\n\npayer_note\x18\x08 \x01(\tH\x06\x88\x01\x01\x42\x0e\n\x0c_amount_msatB\x0b\n\t_quantityB\x15\n\x13_recurrence_counterB\x13\n\x11_recurrence_startB\x13\n\x11_recurrence_labelB\n\n\x08_timeoutB\r\n\x0b_payer_note\"\x9a\x01\n\x14\x46\x65tchinvoiceResponse\x12\x0f\n\x07invoice\x18\x01 \x01(\t\x12)\n\x07\x63hanges\x18\x02 \x01(\x0b\x32\x18.cln.FetchinvoiceChanges\x12\x36\n\x0bnext_period\x18\x03 \x01(\x0b\x32\x1c.cln.FetchinvoiceNext_periodH\x00\x88\x01\x01\x42\x0e\n\x0c_next_period\"\x82\x02\n\x13\x46\x65tchinvoiceChanges\x12!\n\x14\x64\x65scription_appended\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x18\n\x0b\x64\x65scription\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x1b\n\x0evendor_removed\x18\x03 \x01(\tH\x02\x88\x01\x01\x12\x13\n\x06vendor\x18\x04 \x01(\tH\x03\x88\x01\x01\x12%\n\x0b\x61mount_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x04\x88\x01\x01\x42\x17\n\x15_description_appendedB\x0e\n\x0c_descriptionB\x11\n\x0f_vendor_removedB\t\n\x07_vendorB\x0e\n\x0c_amount_msat\"~\n\x17\x46\x65tchinvoiceNext_period\x12\x0f\n\x07\x63ounter\x18\x01 \x01(\x04\x12\x11\n\tstarttime\x18\x02 \x01(\x04\x12\x0f\n\x07\x65ndtime\x18\x03 \x01(\x04\x12\x17\n\x0fpaywindow_start\x18\x04 \x01(\x04\x12\x15\n\rpaywindow_end\x18\x05 \x01(\x04\"\xfb\x03\n\x12\x46undchannelRequest\x12\n\n\x02id\x18\t \x01(\x0c\x12 \n\x06\x61mount\x18\x01 \x01(\x0b\x32\x10.cln.AmountOrAll\x12\"\n\x07\x66\x65\x65rate\x18\x02 \x01(\x0b\x32\x0c.cln.FeerateH\x00\x88\x01\x01\x12\x15\n\x08\x61nnounce\x18\x03 \x01(\x08H\x01\x88\x01\x01\x12\x14\n\x07minconf\x18\n \x01(\rH\x02\x88\x01\x01\x12#\n\tpush_msat\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x03\x88\x01\x01\x12\x15\n\x08\x63lose_to\x18\x06 \x01(\tH\x04\x88\x01\x01\x12%\n\x0brequest_amt\x18\x07 \x01(\x0b\x32\x0b.cln.AmountH\x05\x88\x01\x01\x12\x1a\n\rcompact_lease\x18\x08 \x01(\tH\x06\x88\x01\x01\x12\x1c\n\x05utxos\x18\x0b \x03(\x0b\x32\r.cln.Outpoint\x12\x15\n\x08mindepth\x18\x0c \x01(\rH\x07\x88\x01\x01\x12!\n\x07reserve\x18\r \x01(\x0b\x32\x0b.cln.AmountH\x08\x88\x01\x01\x12\x14\n\x0c\x63hannel_type\x18\x0e \x03(\rB\n\n\x08_feerateB\x0b\n\t_announceB\n\n\x08_minconfB\x0c\n\n_push_msatB\x0b\n\t_close_toB\x0e\n\x0c_request_amtB\x10\n\x0e_compact_leaseB\x0b\n\t_mindepthB\n\n\x08_reserve\"\xe5\x01\n\x13\x46undchannelResponse\x12\n\n\x02tx\x18\x01 \x01(\x0c\x12\x0c\n\x04txid\x18\x02 \x01(\x0c\x12\x0e\n\x06outnum\x18\x03 \x01(\r\x12\x12\n\nchannel_id\x18\x04 \x01(\x0c\x12\x37\n\x0c\x63hannel_type\x18\x07 \x01(\x0b\x32\x1c.cln.FundchannelChannel_typeH\x00\x88\x01\x01\x12\x15\n\x08\x63lose_to\x18\x05 \x01(\x0cH\x01\x88\x01\x01\x12\x15\n\x08mindepth\x18\x06 \x01(\rH\x02\x88\x01\x01\x42\x0f\n\r_channel_typeB\x0b\n\t_close_toB\x0b\n\t_mindepth\"L\n\x17\x46undchannelChannel_type\x12\x0c\n\x04\x62its\x18\x01 \x03(\r\x12#\n\x05names\x18\x02 \x03(\x0e\x32\x14.cln.ChannelTypeName\"\xec\x01\n\x0fGetrouteRequest\x12\n\n\x02id\x18\x01 \x01(\x0c\x12 \n\x0b\x61mount_msat\x18\t \x01(\x0b\x32\x0b.cln.Amount\x12\x12\n\nriskfactor\x18\x03 \x01(\x04\x12\x11\n\x04\x63ltv\x18\x04 \x01(\rH\x00\x88\x01\x01\x12\x13\n\x06\x66romid\x18\x05 \x01(\x0cH\x01\x88\x01\x01\x12\x18\n\x0b\x66uzzpercent\x18\x06 \x01(\rH\x02\x88\x01\x01\x12\x0f\n\x07\x65xclude\x18\x07 \x03(\t\x12\x14\n\x07maxhops\x18\x08 \x01(\rH\x03\x88\x01\x01\x42\x07\n\x05_cltvB\t\n\x07_fromidB\x0e\n\x0c_fuzzpercentB\n\n\x08_maxhops\"5\n\x10GetrouteResponse\x12!\n\x05route\x18\x01 \x03(\x0b\x32\x12.cln.GetrouteRoute\"\xc5\x01\n\rGetrouteRoute\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x0f\n\x07\x63hannel\x18\x02 \x01(\t\x12\x11\n\tdirection\x18\x03 \x01(\r\x12 \n\x0b\x61mount_msat\x18\x04 \x01(\x0b\x32\x0b.cln.Amount\x12\r\n\x05\x64\x65lay\x18\x05 \x01(\r\x12\x34\n\x05style\x18\x06 \x01(\x0e\x32%.cln.GetrouteRoute.GetrouteRouteStyle\"\x1d\n\x12GetrouteRouteStyle\x12\x07\n\x03TLV\x10\x00\"\xb7\x03\n\x13ListforwardsRequest\x12@\n\x06status\x18\x01 \x01(\x0e\x32+.cln.ListforwardsRequest.ListforwardsStatusH\x00\x88\x01\x01\x12\x17\n\nin_channel\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x18\n\x0bout_channel\x18\x03 \x01(\tH\x02\x88\x01\x01\x12>\n\x05index\x18\x04 \x01(\x0e\x32*.cln.ListforwardsRequest.ListforwardsIndexH\x03\x88\x01\x01\x12\x12\n\x05start\x18\x05 \x01(\x04H\x04\x88\x01\x01\x12\x12\n\x05limit\x18\x06 \x01(\rH\x05\x88\x01\x01\"L\n\x12ListforwardsStatus\x12\x0b\n\x07OFFERED\x10\x00\x12\x0b\n\x07SETTLED\x10\x01\x12\x10\n\x0cLOCAL_FAILED\x10\x02\x12\n\n\x06\x46\x41ILED\x10\x03\"-\n\x11ListforwardsIndex\x12\x0b\n\x07\x43REATED\x10\x00\x12\x0b\n\x07UPDATED\x10\x01\x42\t\n\x07_statusB\r\n\x0b_in_channelB\x0e\n\x0c_out_channelB\x08\n\x06_indexB\x08\n\x06_startB\x08\n\x06_limit\"C\n\x14ListforwardsResponse\x12+\n\x08\x66orwards\x18\x01 \x03(\x0b\x32\x19.cln.ListforwardsForwards\"\xba\x05\n\x14ListforwardsForwards\x12\x1a\n\rcreated_index\x18\x0c \x01(\x04H\x00\x88\x01\x01\x12\x12\n\nin_channel\x18\x01 \x01(\t\x12\x17\n\nin_htlc_id\x18\n \x01(\x04H\x01\x88\x01\x01\x12\x1c\n\x07in_msat\x18\x02 \x01(\x0b\x32\x0b.cln.Amount\x12\x44\n\x06status\x18\x03 \x01(\x0e\x32\x34.cln.ListforwardsForwards.ListforwardsForwardsStatus\x12\x15\n\rreceived_time\x18\x04 \x01(\x01\x12\x18\n\x0bout_channel\x18\x05 \x01(\tH\x02\x88\x01\x01\x12\x18\n\x0bout_htlc_id\x18\x0b \x01(\x04H\x03\x88\x01\x01\x12\x1a\n\rupdated_index\x18\r \x01(\x04H\x04\x88\x01\x01\x12G\n\x05style\x18\t \x01(\x0e\x32\x33.cln.ListforwardsForwards.ListforwardsForwardsStyleH\x05\x88\x01\x01\x12\"\n\x08\x66\x65\x65_msat\x18\x07 \x01(\x0b\x32\x0b.cln.AmountH\x06\x88\x01\x01\x12\"\n\x08out_msat\x18\x08 \x01(\x0b\x32\x0b.cln.AmountH\x07\x88\x01\x01\"T\n\x1aListforwardsForwardsStatus\x12\x0b\n\x07OFFERED\x10\x00\x12\x0b\n\x07SETTLED\x10\x01\x12\x10\n\x0cLOCAL_FAILED\x10\x02\x12\n\n\x06\x46\x41ILED\x10\x03\"0\n\x19ListforwardsForwardsStyle\x12\n\n\x06LEGACY\x10\x00\x12\x07\n\x03TLV\x10\x01\x42\x10\n\x0e_created_indexB\r\n\x0b_in_htlc_idB\x0e\n\x0c_out_channelB\x0e\n\x0c_out_htlc_idB\x10\n\x0e_updated_indexB\x08\n\x06_styleB\x0b\n\t_fee_msatB\x0b\n\t_out_msat\"\xdb\x01\n\x0fListpaysRequest\x12\x13\n\x06\x62olt11\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x19\n\x0cpayment_hash\x18\x02 \x01(\x0cH\x01\x88\x01\x01\x12\x38\n\x06status\x18\x03 \x01(\x0e\x32#.cln.ListpaysRequest.ListpaysStatusH\x02\x88\x01\x01\"7\n\x0eListpaysStatus\x12\x0b\n\x07PENDING\x10\x00\x12\x0c\n\x08\x43OMPLETE\x10\x01\x12\n\n\x06\x46\x41ILED\x10\x02\x42\t\n\x07_bolt11B\x0f\n\r_payment_hashB\t\n\x07_status\"3\n\x10ListpaysResponse\x12\x1f\n\x04pays\x18\x01 \x03(\x0b\x32\x11.cln.ListpaysPays\"\xff\x04\n\x0cListpaysPays\x12\x14\n\x0cpayment_hash\x18\x01 \x01(\x0c\x12\x34\n\x06status\x18\x02 \x01(\x0e\x32$.cln.ListpaysPays.ListpaysPaysStatus\x12\x18\n\x0b\x64\x65stination\x18\x03 \x01(\x0cH\x00\x88\x01\x01\x12\x12\n\ncreated_at\x18\x04 \x01(\x04\x12\x19\n\x0c\x63ompleted_at\x18\x0c \x01(\x04H\x01\x88\x01\x01\x12\x12\n\x05label\x18\x05 \x01(\tH\x02\x88\x01\x01\x12\x13\n\x06\x62olt11\x18\x06 \x01(\tH\x03\x88\x01\x01\x12\x18\n\x0b\x64\x65scription\x18\x0b \x01(\tH\x04\x88\x01\x01\x12\x13\n\x06\x62olt12\x18\x07 \x01(\tH\x05\x88\x01\x01\x12%\n\x0b\x61mount_msat\x18\x08 \x01(\x0b\x32\x0b.cln.AmountH\x06\x88\x01\x01\x12*\n\x10\x61mount_sent_msat\x18\t \x01(\x0b\x32\x0b.cln.AmountH\x07\x88\x01\x01\x12\x15\n\x08preimage\x18\r \x01(\x0cH\x08\x88\x01\x01\x12\x1c\n\x0fnumber_of_parts\x18\x0e \x01(\x04H\t\x88\x01\x01\x12\x17\n\nerroronion\x18\n \x01(\x0cH\n\x88\x01\x01\";\n\x12ListpaysPaysStatus\x12\x0b\n\x07PENDING\x10\x00\x12\n\n\x06\x46\x41ILED\x10\x01\x12\x0c\n\x08\x43OMPLETE\x10\x02\x42\x0e\n\x0c_destinationB\x0f\n\r_completed_atB\x08\n\x06_labelB\t\n\x07_bolt11B\x0e\n\x0c_descriptionB\t\n\x07_bolt12B\x0e\n\x0c_amount_msatB\x13\n\x11_amount_sent_msatB\x0b\n\t_preimageB\x12\n\x10_number_of_partsB\r\n\x0b_erroronion\"*\n\x10ListhtlcsRequest\x12\x0f\n\x02id\x18\x01 \x01(\tH\x00\x88\x01\x01\x42\x05\n\x03_id\"7\n\x11ListhtlcsResponse\x12\"\n\x05htlcs\x18\x01 \x03(\x0b\x32\x13.cln.ListhtlcsHtlcs\"\x89\x02\n\x0eListhtlcsHtlcs\x12\x18\n\x10short_channel_id\x18\x01 \x01(\t\x12\n\n\x02id\x18\x02 \x01(\x04\x12\x0e\n\x06\x65xpiry\x18\x03 \x01(\r\x12 \n\x0b\x61mount_msat\x18\x04 \x01(\x0b\x32\x0b.cln.Amount\x12>\n\tdirection\x18\x05 \x01(\x0e\x32+.cln.ListhtlcsHtlcs.ListhtlcsHtlcsDirection\x12\x14\n\x0cpayment_hash\x18\x06 \x01(\x0c\x12\x1d\n\x05state\x18\x07 \x01(\x0e\x32\x0e.cln.HtlcState\"*\n\x17ListhtlcsHtlcsDirection\x12\x07\n\x03OUT\x10\x00\x12\x06\n\x02IN\x10\x01\"Y\n\x0bPingRequest\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x10\n\x03len\x18\x02 \x01(\rH\x00\x88\x01\x01\x12\x16\n\tpongbytes\x18\x03 \x01(\rH\x01\x88\x01\x01\x42\x06\n\x04_lenB\x0c\n\n_pongbytes\"\x1e\n\x0cPingResponse\x12\x0e\n\x06totlen\x18\x01 \x01(\r\"4\n\x14SendcustommsgRequest\x12\x0f\n\x07node_id\x18\x01 \x01(\x0c\x12\x0b\n\x03msg\x18\x02 \x01(\x0c\"\'\n\x15SendcustommsgResponse\x12\x0e\n\x06status\x18\x01 \x01(\t\"\xaa\x02\n\x11SetchannelRequest\x12\n\n\x02id\x18\x01 \x01(\t\x12!\n\x07\x66\x65\x65\x62\x61se\x18\x02 \x01(\x0b\x32\x0b.cln.AmountH\x00\x88\x01\x01\x12\x13\n\x06\x66\x65\x65ppm\x18\x03 \x01(\rH\x01\x88\x01\x01\x12!\n\x07htlcmin\x18\x04 \x01(\x0b\x32\x0b.cln.AmountH\x02\x88\x01\x01\x12!\n\x07htlcmax\x18\x05 \x01(\x0b\x32\x0b.cln.AmountH\x03\x88\x01\x01\x12\x19\n\x0c\x65nforcedelay\x18\x06 \x01(\rH\x04\x88\x01\x01\x12\x1c\n\x0fignorefeelimits\x18\x07 \x01(\x08H\x05\x88\x01\x01\x42\n\n\x08_feebaseB\t\n\x07_feeppmB\n\n\x08_htlcminB\n\n\x08_htlcmaxB\x0f\n\r_enforcedelayB\x12\n\x10_ignorefeelimits\"?\n\x12SetchannelResponse\x12)\n\x08\x63hannels\x18\x01 \x03(\x0b\x32\x17.cln.SetchannelChannels\"\xca\x03\n\x12SetchannelChannels\x12\x0f\n\x07peer_id\x18\x01 \x01(\x0c\x12\x12\n\nchannel_id\x18\x02 \x01(\x0c\x12\x1d\n\x10short_channel_id\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\"\n\rfee_base_msat\x18\x04 \x01(\x0b\x32\x0b.cln.Amount\x12#\n\x1b\x66\x65\x65_proportional_millionths\x18\x05 \x01(\r\x12\x1e\n\x11ignore_fee_limits\x18\n \x01(\x08H\x01\x88\x01\x01\x12*\n\x15minimum_htlc_out_msat\x18\x06 \x01(\x0b\x32\x0b.cln.Amount\x12$\n\x17warning_htlcmin_too_low\x18\x07 \x01(\tH\x02\x88\x01\x01\x12*\n\x15maximum_htlc_out_msat\x18\x08 \x01(\x0b\x32\x0b.cln.Amount\x12%\n\x18warning_htlcmax_too_high\x18\t \x01(\tH\x03\x88\x01\x01\x42\x13\n\x11_short_channel_idB\x14\n\x12_ignore_fee_limitsB\x1a\n\x18_warning_htlcmin_too_lowB\x1b\n\x19_warning_htlcmax_too_high\"\'\n\x12SigninvoiceRequest\x12\x11\n\tinvstring\x18\x01 \x01(\t\"%\n\x13SigninvoiceResponse\x12\x0e\n\x06\x62olt11\x18\x01 \x01(\t\"%\n\x12SignmessageRequest\x12\x0f\n\x07message\x18\x01 \x01(\t\"F\n\x13SignmessageResponse\x12\x11\n\tsignature\x18\x01 \x01(\x0c\x12\r\n\x05recid\x18\x02 \x01(\x0c\x12\r\n\x05zbase\x18\x03 \x01(\t\"O\n\x16WaitblockheightRequest\x12\x13\n\x0b\x62lockheight\x18\x01 \x01(\r\x12\x14\n\x07timeout\x18\x02 \x01(\rH\x00\x88\x01\x01\x42\n\n\x08_timeout\".\n\x17WaitblockheightResponse\x12\x13\n\x0b\x62lockheight\x18\x01 \x01(\r\"\xf9\x01\n\x0bWaitRequest\x12\x31\n\tsubsystem\x18\x01 \x01(\x0e\x32\x1e.cln.WaitRequest.WaitSubsystem\x12\x31\n\tindexname\x18\x02 \x01(\x0e\x32\x1e.cln.WaitRequest.WaitIndexname\x12\x11\n\tnextvalue\x18\x03 \x01(\x04\"9\n\rWaitSubsystem\x12\x0c\n\x08INVOICES\x10\x00\x12\x0c\n\x08\x46ORWARDS\x10\x01\x12\x0c\n\x08SENDPAYS\x10\x02\"6\n\rWaitIndexname\x12\x0b\n\x07\x43REATED\x10\x00\x12\x0b\n\x07UPDATED\x10\x01\x12\x0b\n\x07\x44\x45LETED\x10\x02\"\xe3\x01\n\x0cWaitResponse\x12\x32\n\tsubsystem\x18\x01 \x01(\x0e\x32\x1f.cln.WaitResponse.WaitSubsystem\x12\x14\n\x07\x63reated\x18\x02 \x01(\x04H\x00\x88\x01\x01\x12\x14\n\x07updated\x18\x03 \x01(\x04H\x01\x88\x01\x01\x12\x14\n\x07\x64\x65leted\x18\x04 \x01(\x04H\x02\x88\x01\x01\"9\n\rWaitSubsystem\x12\x0c\n\x08INVOICES\x10\x00\x12\x0c\n\x08\x46ORWARDS\x10\x01\x12\x0c\n\x08SENDPAYS\x10\x02\x42\n\n\x08_createdB\n\n\x08_updatedB\n\n\x08_deleted\"\r\n\x0bStopRequest\"\x0e\n\x0cStopResponse\"\xa7\x01\n\x18PreapprovekeysendRequest\x12\x18\n\x0b\x64\x65stination\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x12\x19\n\x0cpayment_hash\x18\x02 \x01(\x0cH\x01\x88\x01\x01\x12%\n\x0b\x61mount_msat\x18\x03 \x01(\x0b\x32\x0b.cln.AmountH\x02\x88\x01\x01\x42\x0e\n\x0c_destinationB\x0f\n\r_payment_hashB\x0e\n\x0c_amount_msat\"\x1b\n\x19PreapprovekeysendResponse\":\n\x18PreapproveinvoiceRequest\x12\x13\n\x06\x62olt11\x18\x01 \x01(\tH\x00\x88\x01\x01\x42\t\n\x07_bolt11\"\x1b\n\x19PreapproveinvoiceResponse\"\x15\n\x13StaticbackupRequest\"#\n\x14StaticbackupResponse\x12\x0b\n\x03scb\x18\x01 \x03(\x0c\x32\xa2\x1f\n\x04Node\x12\x36\n\x07Getinfo\x12\x13.cln.GetinfoRequest\x1a\x14.cln.GetinfoResponse\"\x00\x12<\n\tListPeers\x12\x15.cln.ListpeersRequest\x1a\x16.cln.ListpeersResponse\"\x00\x12<\n\tListFunds\x12\x15.cln.ListfundsRequest\x1a\x16.cln.ListfundsResponse\"\x00\x12\x36\n\x07SendPay\x12\x13.cln.SendpayRequest\x1a\x14.cln.SendpayResponse\"\x00\x12\x45\n\x0cListChannels\x12\x18.cln.ListchannelsRequest\x1a\x19.cln.ListchannelsResponse\"\x00\x12<\n\tAddGossip\x12\x15.cln.AddgossipRequest\x1a\x16.cln.AddgossipResponse\"\x00\x12Q\n\x10\x41utoCleanInvoice\x12\x1c.cln.AutocleaninvoiceRequest\x1a\x1d.cln.AutocleaninvoiceResponse\"\x00\x12\x45\n\x0c\x43heckMessage\x12\x18.cln.CheckmessageRequest\x1a\x19.cln.CheckmessageResponse\"\x00\x12\x30\n\x05\x43lose\x12\x11.cln.CloseRequest\x1a\x12.cln.CloseResponse\"\x00\x12:\n\x0b\x43onnectPeer\x12\x13.cln.ConnectRequest\x1a\x14.cln.ConnectResponse\"\x00\x12H\n\rCreateInvoice\x12\x19.cln.CreateinvoiceRequest\x1a\x1a.cln.CreateinvoiceResponse\"\x00\x12<\n\tDatastore\x12\x15.cln.DatastoreRequest\x1a\x16.cln.DatastoreResponse\"\x00\x12K\n\x0e\x44\x61tastoreUsage\x12\x1a.cln.DatastoreusageRequest\x1a\x1b.cln.DatastoreusageResponse\"\x00\x12\x42\n\x0b\x43reateOnion\x12\x17.cln.CreateonionRequest\x1a\x18.cln.CreateonionResponse\"\x00\x12\x45\n\x0c\x44\x65lDatastore\x12\x18.cln.DeldatastoreRequest\x1a\x19.cln.DeldatastoreResponse\"\x00\x12T\n\x11\x44\x65lExpiredInvoice\x12\x1d.cln.DelexpiredinvoiceRequest\x1a\x1e.cln.DelexpiredinvoiceResponse\"\x00\x12?\n\nDelInvoice\x12\x16.cln.DelinvoiceRequest\x1a\x17.cln.DelinvoiceResponse\"\x00\x12\x36\n\x07Invoice\x12\x13.cln.InvoiceRequest\x1a\x14.cln.InvoiceResponse\"\x00\x12H\n\rListDatastore\x12\x19.cln.ListdatastoreRequest\x1a\x1a.cln.ListdatastoreResponse\"\x00\x12\x45\n\x0cListInvoices\x12\x18.cln.ListinvoicesRequest\x1a\x19.cln.ListinvoicesResponse\"\x00\x12<\n\tSendOnion\x12\x15.cln.SendonionRequest\x1a\x16.cln.SendonionResponse\"\x00\x12\x45\n\x0cListSendPays\x12\x18.cln.ListsendpaysRequest\x1a\x19.cln.ListsendpaysResponse\"\x00\x12Q\n\x10ListTransactions\x12\x1c.cln.ListtransactionsRequest\x1a\x1d.cln.ListtransactionsResponse\"\x00\x12*\n\x03Pay\x12\x0f.cln.PayRequest\x1a\x10.cln.PayResponse\"\x00\x12<\n\tListNodes\x12\x15.cln.ListnodesRequest\x1a\x16.cln.ListnodesResponse\"\x00\x12K\n\x0eWaitAnyInvoice\x12\x1a.cln.WaitanyinvoiceRequest\x1a\x1b.cln.WaitanyinvoiceResponse\"\x00\x12\x42\n\x0bWaitInvoice\x12\x17.cln.WaitinvoiceRequest\x1a\x18.cln.WaitinvoiceResponse\"\x00\x12\x42\n\x0bWaitSendPay\x12\x17.cln.WaitsendpayRequest\x1a\x18.cln.WaitsendpayResponse\"\x00\x12\x36\n\x07NewAddr\x12\x13.cln.NewaddrRequest\x1a\x14.cln.NewaddrResponse\"\x00\x12\x39\n\x08Withdraw\x12\x14.cln.WithdrawRequest\x1a\x15.cln.WithdrawResponse\"\x00\x12\x36\n\x07KeySend\x12\x13.cln.KeysendRequest\x1a\x14.cln.KeysendResponse\"\x00\x12\x39\n\x08\x46undPsbt\x12\x14.cln.FundpsbtRequest\x1a\x15.cln.FundpsbtResponse\"\x00\x12\x39\n\x08SendPsbt\x12\x14.cln.SendpsbtRequest\x1a\x15.cln.SendpsbtResponse\"\x00\x12\x39\n\x08SignPsbt\x12\x14.cln.SignpsbtRequest\x1a\x15.cln.SignpsbtResponse\"\x00\x12\x39\n\x08UtxoPsbt\x12\x14.cln.UtxopsbtRequest\x1a\x15.cln.UtxopsbtResponse\"\x00\x12<\n\tTxDiscard\x12\x15.cln.TxdiscardRequest\x1a\x16.cln.TxdiscardResponse\"\x00\x12<\n\tTxPrepare\x12\x15.cln.TxprepareRequest\x1a\x16.cln.TxprepareResponse\"\x00\x12\x33\n\x06TxSend\x12\x12.cln.TxsendRequest\x1a\x13.cln.TxsendResponse\"\x00\x12Q\n\x10ListPeerChannels\x12\x1c.cln.ListpeerchannelsRequest\x1a\x1d.cln.ListpeerchannelsResponse\"\x00\x12W\n\x12ListClosedChannels\x12\x1e.cln.ListclosedchannelsRequest\x1a\x1f.cln.ListclosedchannelsResponse\"\x00\x12<\n\tDecodePay\x12\x15.cln.DecodepayRequest\x1a\x16.cln.DecodepayResponse\"\x00\x12\x33\n\x06\x44\x65\x63ode\x12\x12.cln.DecodeRequest\x1a\x13.cln.DecodeResponse\"\x00\x12?\n\nDisconnect\x12\x16.cln.DisconnectRequest\x1a\x17.cln.DisconnectResponse\"\x00\x12\x39\n\x08\x46\x65\x65rates\x12\x14.cln.FeeratesRequest\x1a\x15.cln.FeeratesResponse\"\x00\x12\x45\n\x0c\x46\x65tchInvoice\x12\x18.cln.FetchinvoiceRequest\x1a\x19.cln.FetchinvoiceResponse\"\x00\x12\x42\n\x0b\x46undChannel\x12\x17.cln.FundchannelRequest\x1a\x18.cln.FundchannelResponse\"\x00\x12\x39\n\x08GetRoute\x12\x14.cln.GetrouteRequest\x1a\x15.cln.GetrouteResponse\"\x00\x12\x45\n\x0cListForwards\x12\x18.cln.ListforwardsRequest\x1a\x19.cln.ListforwardsResponse\"\x00\x12\x39\n\x08ListPays\x12\x14.cln.ListpaysRequest\x1a\x15.cln.ListpaysResponse\"\x00\x12<\n\tListHtlcs\x12\x15.cln.ListhtlcsRequest\x1a\x16.cln.ListhtlcsResponse\"\x00\x12-\n\x04Ping\x12\x10.cln.PingRequest\x1a\x11.cln.PingResponse\"\x00\x12H\n\rSendCustomMsg\x12\x19.cln.SendcustommsgRequest\x1a\x1a.cln.SendcustommsgResponse\"\x00\x12?\n\nSetChannel\x12\x16.cln.SetchannelRequest\x1a\x17.cln.SetchannelResponse\"\x00\x12\x42\n\x0bSignInvoice\x12\x17.cln.SigninvoiceRequest\x1a\x18.cln.SigninvoiceResponse\"\x00\x12\x42\n\x0bSignMessage\x12\x17.cln.SignmessageRequest\x1a\x18.cln.SignmessageResponse\"\x00\x12N\n\x0fWaitBlockHeight\x12\x1b.cln.WaitblockheightRequest\x1a\x1c.cln.WaitblockheightResponse\"\x00\x12-\n\x04Wait\x12\x10.cln.WaitRequest\x1a\x11.cln.WaitResponse\"\x00\x12-\n\x04Stop\x12\x10.cln.StopRequest\x1a\x11.cln.StopResponse\"\x00\x12T\n\x11PreApproveKeysend\x12\x1d.cln.PreapprovekeysendRequest\x1a\x1e.cln.PreapprovekeysendResponse\"\x00\x12T\n\x11PreApproveInvoice\x12\x1d.cln.PreapproveinvoiceRequest\x1a\x1e.cln.PreapproveinvoiceResponse\"\x00\x12\x45\n\x0cStaticBackup\x12\x18.cln.StaticbackupRequest\x1a\x19.cln.StaticbackupResponse\"\x00\x62\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -298,193 +298,193 @@ _globals['_LISTPEERCHANNELSRESPONSE']._serialized_start=25722 _globals['_LISTPEERCHANNELSRESPONSE']._serialized_end=25797 _globals['_LISTPEERCHANNELSCHANNELS']._serialized_start=25800 - _globals['_LISTPEERCHANNELSCHANNELS']._serialized_end=29162 - _globals['_LISTPEERCHANNELSCHANNELS_LISTPEERCHANNELSCHANNELSSTATE']._serialized_start=27851 - _globals['_LISTPEERCHANNELSCHANNELS_LISTPEERCHANNELSCHANNELSSTATE']._serialized_end=28235 - _globals['_LISTPEERCHANNELSCHANNELSUPDATES']._serialized_start=29165 - _globals['_LISTPEERCHANNELSCHANNELSUPDATES']._serialized_end=29347 - _globals['_LISTPEERCHANNELSCHANNELSUPDATESLOCAL']._serialized_start=29350 - _globals['_LISTPEERCHANNELSCHANNELSUPDATESLOCAL']._serialized_end=29709 - _globals['_LISTPEERCHANNELSCHANNELSUPDATESREMOTE']._serialized_start=29712 - _globals['_LISTPEERCHANNELSCHANNELSUPDATESREMOTE']._serialized_end=30072 - _globals['_LISTPEERCHANNELSCHANNELSFEERATE']._serialized_start=30074 - _globals['_LISTPEERCHANNELSCHANNELSFEERATE']._serialized_end=30167 - _globals['_LISTPEERCHANNELSCHANNELSINFLIGHT']._serialized_start=30170 - _globals['_LISTPEERCHANNELSCHANNELSINFLIGHT']._serialized_end=30554 - _globals['_LISTPEERCHANNELSCHANNELSFUNDING']._serialized_start=30557 - _globals['_LISTPEERCHANNELSCHANNELSFUNDING']._serialized_end=30895 - _globals['_LISTPEERCHANNELSCHANNELSALIAS']._serialized_start=30897 - _globals['_LISTPEERCHANNELSCHANNELSALIAS']._serialized_end=30990 - _globals['_LISTPEERCHANNELSCHANNELSHTLCS']._serialized_start=30993 - _globals['_LISTPEERCHANNELSCHANNELSHTLCS']._serialized_end=31475 - _globals['_LISTPEERCHANNELSCHANNELSHTLCS_LISTPEERCHANNELSCHANNELSHTLCSDIRECTION']._serialized_start=31314 - _globals['_LISTPEERCHANNELSCHANNELSHTLCS_LISTPEERCHANNELSCHANNELSHTLCSDIRECTION']._serialized_end=31371 - _globals['_LISTCLOSEDCHANNELSREQUEST']._serialized_start=31477 - _globals['_LISTCLOSEDCHANNELSREQUEST']._serialized_end=31528 - _globals['_LISTCLOSEDCHANNELSRESPONSE']._serialized_start=31530 - _globals['_LISTCLOSEDCHANNELSRESPONSE']._serialized_end=31621 - _globals['_LISTCLOSEDCHANNELSCLOSEDCHANNELS']._serialized_start=31624 - _globals['_LISTCLOSEDCHANNELSCLOSEDCHANNELS']._serialized_end=32826 - _globals['_LISTCLOSEDCHANNELSCLOSEDCHANNELS_LISTCLOSEDCHANNELSCLOSEDCHANNELSCLOSE_CAUSE']._serialized_start=32524 - _globals['_LISTCLOSEDCHANNELSCLOSEDCHANNELS_LISTCLOSEDCHANNELSCLOSEDCHANNELSCLOSE_CAUSE']._serialized_end=32642 - _globals['_LISTCLOSEDCHANNELSCLOSEDCHANNELSALIAS']._serialized_start=32828 - _globals['_LISTCLOSEDCHANNELSCLOSEDCHANNELSALIAS']._serialized_end=32929 - _globals['_DECODEPAYREQUEST']._serialized_start=32931 - _globals['_DECODEPAYREQUEST']._serialized_end=33007 - _globals['_DECODEPAYRESPONSE']._serialized_start=33010 - _globals['_DECODEPAYRESPONSE']._serialized_end=33535 - _globals['_DECODEPAYFALLBACKS']._serialized_start=33538 - _globals['_DECODEPAYFALLBACKS']._serialized_end=33746 - _globals['_DECODEPAYFALLBACKS_DECODEPAYFALLBACKSTYPE']._serialized_start=33659 - _globals['_DECODEPAYFALLBACKS_DECODEPAYFALLBACKSTYPE']._serialized_end=33737 - _globals['_DECODEPAYEXTRA']._serialized_start=33748 - _globals['_DECODEPAYEXTRA']._serialized_end=33791 - _globals['_DECODEREQUEST']._serialized_start=33793 - _globals['_DECODEREQUEST']._serialized_end=33824 - _globals['_DECODERESPONSE']._serialized_start=33827 - _globals['_DECODERESPONSE']._serialized_end=38155 - _globals['_DECODERESPONSE_DECODETYPE']._serialized_start=36420 - _globals['_DECODERESPONSE_DECODETYPE']._serialized_end=36551 - _globals['_DECODEOFFER_PATHS']._serialized_start=38157 - _globals['_DECODEOFFER_PATHS']._serialized_end=38217 - _globals['_DECODEOFFER_RECURRENCEPAYWINDOW']._serialized_start=38220 - _globals['_DECODEOFFER_RECURRENCEPAYWINDOW']._serialized_end=38358 - _globals['_DECODEINVOICE_PATHSPATH']._serialized_start=38360 - _globals['_DECODEINVOICE_PATHSPATH']._serialized_end=38444 - _globals['_DECODEINVOICE_FALLBACKS']._serialized_start=38446 - _globals['_DECODEINVOICE_FALLBACKS']._serialized_end=38535 - _globals['_DECODEFALLBACKS']._serialized_start=38537 - _globals['_DECODEFALLBACKS']._serialized_end=38656 - _globals['_DECODEEXTRA']._serialized_start=38658 - _globals['_DECODEEXTRA']._serialized_end=38698 - _globals['_DECODERESTRICTIONS']._serialized_start=38700 - _globals['_DECODERESTRICTIONS']._serialized_end=38759 - _globals['_DISCONNECTREQUEST']._serialized_start=38761 - _globals['_DISCONNECTREQUEST']._serialized_end=38822 - _globals['_DISCONNECTRESPONSE']._serialized_start=38824 - _globals['_DISCONNECTRESPONSE']._serialized_end=38844 - _globals['_FEERATESREQUEST']._serialized_start=38846 - _globals['_FEERATESREQUEST']._serialized_end=38953 - _globals['_FEERATESREQUEST_FEERATESSTYLE']._serialized_start=38916 - _globals['_FEERATESREQUEST_FEERATESSTYLE']._serialized_end=38953 - _globals['_FEERATESRESPONSE']._serialized_start=38956 - _globals['_FEERATESRESPONSE']._serialized_end=39240 - _globals['_FEERATESPERKB']._serialized_start=39243 - _globals['_FEERATESPERKB']._serialized_end=39710 - _globals['_FEERATESPERKBESTIMATES']._serialized_start=39713 - _globals['_FEERATESPERKBESTIMATES']._serialized_end=39863 - _globals['_FEERATESPERKW']._serialized_start=39866 - _globals['_FEERATESPERKW']._serialized_end=40333 - _globals['_FEERATESPERKWESTIMATES']._serialized_start=40336 - _globals['_FEERATESPERKWESTIMATES']._serialized_end=40486 - _globals['_FEERATESONCHAIN_FEE_ESTIMATES']._serialized_start=40489 - _globals['_FEERATESONCHAIN_FEE_ESTIMATES']._serialized_end=40772 - _globals['_FETCHINVOICEREQUEST']._serialized_start=40775 - _globals['_FETCHINVOICEREQUEST']._serialized_end=41136 - _globals['_FETCHINVOICERESPONSE']._serialized_start=41139 - _globals['_FETCHINVOICERESPONSE']._serialized_end=41293 - _globals['_FETCHINVOICECHANGES']._serialized_start=41296 - _globals['_FETCHINVOICECHANGES']._serialized_end=41554 - _globals['_FETCHINVOICENEXT_PERIOD']._serialized_start=41556 - _globals['_FETCHINVOICENEXT_PERIOD']._serialized_end=41682 - _globals['_FUNDCHANNELREQUEST']._serialized_start=41685 - _globals['_FUNDCHANNELREQUEST']._serialized_end=42192 - _globals['_FUNDCHANNELRESPONSE']._serialized_start=42195 - _globals['_FUNDCHANNELRESPONSE']._serialized_end=42424 - _globals['_FUNDCHANNELCHANNEL_TYPE']._serialized_start=42426 - _globals['_FUNDCHANNELCHANNEL_TYPE']._serialized_end=42502 - _globals['_GETROUTEREQUEST']._serialized_start=42505 - _globals['_GETROUTEREQUEST']._serialized_end=42741 - _globals['_GETROUTERESPONSE']._serialized_start=42743 - _globals['_GETROUTERESPONSE']._serialized_end=42796 - _globals['_GETROUTEROUTE']._serialized_start=42799 - _globals['_GETROUTEROUTE']._serialized_end=42996 - _globals['_GETROUTEROUTE_GETROUTEROUTESTYLE']._serialized_start=42967 - _globals['_GETROUTEROUTE_GETROUTEROUTESTYLE']._serialized_end=42996 - _globals['_LISTFORWARDSREQUEST']._serialized_start=42999 - _globals['_LISTFORWARDSREQUEST']._serialized_end=43438 - _globals['_LISTFORWARDSREQUEST_LISTFORWARDSSTATUS']._serialized_start=43243 - _globals['_LISTFORWARDSREQUEST_LISTFORWARDSSTATUS']._serialized_end=43319 - _globals['_LISTFORWARDSREQUEST_LISTFORWARDSINDEX']._serialized_start=43321 - _globals['_LISTFORWARDSREQUEST_LISTFORWARDSINDEX']._serialized_end=43366 - _globals['_LISTFORWARDSRESPONSE']._serialized_start=43440 - _globals['_LISTFORWARDSRESPONSE']._serialized_end=43507 - _globals['_LISTFORWARDSFORWARDS']._serialized_start=43510 - _globals['_LISTFORWARDSFORWARDS']._serialized_end=44208 - _globals['_LISTFORWARDSFORWARDS_LISTFORWARDSFORWARDSSTATUS']._serialized_start=43955 - _globals['_LISTFORWARDSFORWARDS_LISTFORWARDSFORWARDSSTATUS']._serialized_end=44039 - _globals['_LISTFORWARDSFORWARDS_LISTFORWARDSFORWARDSSTYLE']._serialized_start=44041 - _globals['_LISTFORWARDSFORWARDS_LISTFORWARDSFORWARDSSTYLE']._serialized_end=44089 - _globals['_LISTPAYSREQUEST']._serialized_start=44211 - _globals['_LISTPAYSREQUEST']._serialized_end=44430 - _globals['_LISTPAYSREQUEST_LISTPAYSSTATUS']._serialized_start=44336 - _globals['_LISTPAYSREQUEST_LISTPAYSSTATUS']._serialized_end=44391 - _globals['_LISTPAYSRESPONSE']._serialized_start=44432 - _globals['_LISTPAYSRESPONSE']._serialized_end=44483 - _globals['_LISTPAYSPAYS']._serialized_start=44486 - _globals['_LISTPAYSPAYS']._serialized_end=45125 - _globals['_LISTPAYSPAYS_LISTPAYSPAYSSTATUS']._serialized_start=44900 - _globals['_LISTPAYSPAYS_LISTPAYSPAYSSTATUS']._serialized_end=44959 - _globals['_LISTHTLCSREQUEST']._serialized_start=45127 - _globals['_LISTHTLCSREQUEST']._serialized_end=45169 - _globals['_LISTHTLCSRESPONSE']._serialized_start=45171 - _globals['_LISTHTLCSRESPONSE']._serialized_end=45226 - _globals['_LISTHTLCSHTLCS']._serialized_start=45229 - _globals['_LISTHTLCSHTLCS']._serialized_end=45494 - _globals['_LISTHTLCSHTLCS_LISTHTLCSHTLCSDIRECTION']._serialized_start=45452 - _globals['_LISTHTLCSHTLCS_LISTHTLCSHTLCSDIRECTION']._serialized_end=45494 - _globals['_PINGREQUEST']._serialized_start=45496 - _globals['_PINGREQUEST']._serialized_end=45585 - _globals['_PINGRESPONSE']._serialized_start=45587 - _globals['_PINGRESPONSE']._serialized_end=45617 - _globals['_SENDCUSTOMMSGREQUEST']._serialized_start=45619 - _globals['_SENDCUSTOMMSGREQUEST']._serialized_end=45671 - _globals['_SENDCUSTOMMSGRESPONSE']._serialized_start=45673 - _globals['_SENDCUSTOMMSGRESPONSE']._serialized_end=45712 - _globals['_SETCHANNELREQUEST']._serialized_start=45715 - _globals['_SETCHANNELREQUEST']._serialized_end=46013 - _globals['_SETCHANNELRESPONSE']._serialized_start=46015 - _globals['_SETCHANNELRESPONSE']._serialized_end=46078 - _globals['_SETCHANNELCHANNELS']._serialized_start=46081 - _globals['_SETCHANNELCHANNELS']._serialized_end=46539 - _globals['_SIGNINVOICEREQUEST']._serialized_start=46541 - _globals['_SIGNINVOICEREQUEST']._serialized_end=46580 - _globals['_SIGNINVOICERESPONSE']._serialized_start=46582 - _globals['_SIGNINVOICERESPONSE']._serialized_end=46619 - _globals['_SIGNMESSAGEREQUEST']._serialized_start=46621 - _globals['_SIGNMESSAGEREQUEST']._serialized_end=46658 - _globals['_SIGNMESSAGERESPONSE']._serialized_start=46660 - _globals['_SIGNMESSAGERESPONSE']._serialized_end=46730 - _globals['_WAITBLOCKHEIGHTREQUEST']._serialized_start=46732 - _globals['_WAITBLOCKHEIGHTREQUEST']._serialized_end=46811 - _globals['_WAITBLOCKHEIGHTRESPONSE']._serialized_start=46813 - _globals['_WAITBLOCKHEIGHTRESPONSE']._serialized_end=46859 - _globals['_WAITREQUEST']._serialized_start=46862 - _globals['_WAITREQUEST']._serialized_end=47111 - _globals['_WAITREQUEST_WAITSUBSYSTEM']._serialized_start=46998 - _globals['_WAITREQUEST_WAITSUBSYSTEM']._serialized_end=47055 - _globals['_WAITREQUEST_WAITINDEXNAME']._serialized_start=47057 - _globals['_WAITREQUEST_WAITINDEXNAME']._serialized_end=47111 - _globals['_WAITRESPONSE']._serialized_start=47114 - _globals['_WAITRESPONSE']._serialized_end=47341 - _globals['_WAITRESPONSE_WAITSUBSYSTEM']._serialized_start=46998 - _globals['_WAITRESPONSE_WAITSUBSYSTEM']._serialized_end=47055 - _globals['_STOPREQUEST']._serialized_start=47343 - _globals['_STOPREQUEST']._serialized_end=47356 - _globals['_STOPRESPONSE']._serialized_start=47358 - _globals['_STOPRESPONSE']._serialized_end=47372 - _globals['_PREAPPROVEKEYSENDREQUEST']._serialized_start=47375 - _globals['_PREAPPROVEKEYSENDREQUEST']._serialized_end=47542 - _globals['_PREAPPROVEKEYSENDRESPONSE']._serialized_start=47544 - _globals['_PREAPPROVEKEYSENDRESPONSE']._serialized_end=47571 - _globals['_PREAPPROVEINVOICEREQUEST']._serialized_start=47573 - _globals['_PREAPPROVEINVOICEREQUEST']._serialized_end=47631 - _globals['_PREAPPROVEINVOICERESPONSE']._serialized_start=47633 - _globals['_PREAPPROVEINVOICERESPONSE']._serialized_end=47660 - _globals['_STATICBACKUPREQUEST']._serialized_start=47662 - _globals['_STATICBACKUPREQUEST']._serialized_end=47683 - _globals['_STATICBACKUPRESPONSE']._serialized_start=47685 - _globals['_STATICBACKUPRESPONSE']._serialized_end=47720 - _globals['_NODE']._serialized_start=47723 - _globals['_NODE']._serialized_end=51725 + _globals['_LISTPEERCHANNELSCHANNELS']._serialized_end=29226 + _globals['_LISTPEERCHANNELSCHANNELS_LISTPEERCHANNELSCHANNELSSTATE']._serialized_start=27888 + _globals['_LISTPEERCHANNELSCHANNELS_LISTPEERCHANNELSCHANNELSSTATE']._serialized_end=28272 + _globals['_LISTPEERCHANNELSCHANNELSUPDATES']._serialized_start=29229 + _globals['_LISTPEERCHANNELSCHANNELSUPDATES']._serialized_end=29411 + _globals['_LISTPEERCHANNELSCHANNELSUPDATESLOCAL']._serialized_start=29414 + _globals['_LISTPEERCHANNELSCHANNELSUPDATESLOCAL']._serialized_end=29773 + _globals['_LISTPEERCHANNELSCHANNELSUPDATESREMOTE']._serialized_start=29776 + _globals['_LISTPEERCHANNELSCHANNELSUPDATESREMOTE']._serialized_end=30136 + _globals['_LISTPEERCHANNELSCHANNELSFEERATE']._serialized_start=30138 + _globals['_LISTPEERCHANNELSCHANNELSFEERATE']._serialized_end=30231 + _globals['_LISTPEERCHANNELSCHANNELSINFLIGHT']._serialized_start=30234 + _globals['_LISTPEERCHANNELSCHANNELSINFLIGHT']._serialized_end=30618 + _globals['_LISTPEERCHANNELSCHANNELSFUNDING']._serialized_start=30621 + _globals['_LISTPEERCHANNELSCHANNELSFUNDING']._serialized_end=30959 + _globals['_LISTPEERCHANNELSCHANNELSALIAS']._serialized_start=30961 + _globals['_LISTPEERCHANNELSCHANNELSALIAS']._serialized_end=31054 + _globals['_LISTPEERCHANNELSCHANNELSHTLCS']._serialized_start=31057 + _globals['_LISTPEERCHANNELSCHANNELSHTLCS']._serialized_end=31539 + _globals['_LISTPEERCHANNELSCHANNELSHTLCS_LISTPEERCHANNELSCHANNELSHTLCSDIRECTION']._serialized_start=31378 + _globals['_LISTPEERCHANNELSCHANNELSHTLCS_LISTPEERCHANNELSCHANNELSHTLCSDIRECTION']._serialized_end=31435 + _globals['_LISTCLOSEDCHANNELSREQUEST']._serialized_start=31541 + _globals['_LISTCLOSEDCHANNELSREQUEST']._serialized_end=31592 + _globals['_LISTCLOSEDCHANNELSRESPONSE']._serialized_start=31594 + _globals['_LISTCLOSEDCHANNELSRESPONSE']._serialized_end=31685 + _globals['_LISTCLOSEDCHANNELSCLOSEDCHANNELS']._serialized_start=31688 + _globals['_LISTCLOSEDCHANNELSCLOSEDCHANNELS']._serialized_end=32954 + _globals['_LISTCLOSEDCHANNELSCLOSEDCHANNELS_LISTCLOSEDCHANNELSCLOSEDCHANNELSCLOSE_CAUSE']._serialized_start=32625 + _globals['_LISTCLOSEDCHANNELSCLOSEDCHANNELS_LISTCLOSEDCHANNELSCLOSEDCHANNELSCLOSE_CAUSE']._serialized_end=32743 + _globals['_LISTCLOSEDCHANNELSCLOSEDCHANNELSALIAS']._serialized_start=32956 + _globals['_LISTCLOSEDCHANNELSCLOSEDCHANNELSALIAS']._serialized_end=33057 + _globals['_DECODEPAYREQUEST']._serialized_start=33059 + _globals['_DECODEPAYREQUEST']._serialized_end=33135 + _globals['_DECODEPAYRESPONSE']._serialized_start=33138 + _globals['_DECODEPAYRESPONSE']._serialized_end=33663 + _globals['_DECODEPAYFALLBACKS']._serialized_start=33666 + _globals['_DECODEPAYFALLBACKS']._serialized_end=33874 + _globals['_DECODEPAYFALLBACKS_DECODEPAYFALLBACKSTYPE']._serialized_start=33787 + _globals['_DECODEPAYFALLBACKS_DECODEPAYFALLBACKSTYPE']._serialized_end=33865 + _globals['_DECODEPAYEXTRA']._serialized_start=33876 + _globals['_DECODEPAYEXTRA']._serialized_end=33919 + _globals['_DECODEREQUEST']._serialized_start=33921 + _globals['_DECODEREQUEST']._serialized_end=33952 + _globals['_DECODERESPONSE']._serialized_start=33955 + _globals['_DECODERESPONSE']._serialized_end=38283 + _globals['_DECODERESPONSE_DECODETYPE']._serialized_start=36548 + _globals['_DECODERESPONSE_DECODETYPE']._serialized_end=36679 + _globals['_DECODEOFFER_PATHS']._serialized_start=38285 + _globals['_DECODEOFFER_PATHS']._serialized_end=38345 + _globals['_DECODEOFFER_RECURRENCEPAYWINDOW']._serialized_start=38348 + _globals['_DECODEOFFER_RECURRENCEPAYWINDOW']._serialized_end=38486 + _globals['_DECODEINVOICE_PATHSPATH']._serialized_start=38488 + _globals['_DECODEINVOICE_PATHSPATH']._serialized_end=38572 + _globals['_DECODEINVOICE_FALLBACKS']._serialized_start=38574 + _globals['_DECODEINVOICE_FALLBACKS']._serialized_end=38663 + _globals['_DECODEFALLBACKS']._serialized_start=38665 + _globals['_DECODEFALLBACKS']._serialized_end=38784 + _globals['_DECODEEXTRA']._serialized_start=38786 + _globals['_DECODEEXTRA']._serialized_end=38826 + _globals['_DECODERESTRICTIONS']._serialized_start=38828 + _globals['_DECODERESTRICTIONS']._serialized_end=38887 + _globals['_DISCONNECTREQUEST']._serialized_start=38889 + _globals['_DISCONNECTREQUEST']._serialized_end=38950 + _globals['_DISCONNECTRESPONSE']._serialized_start=38952 + _globals['_DISCONNECTRESPONSE']._serialized_end=38972 + _globals['_FEERATESREQUEST']._serialized_start=38974 + _globals['_FEERATESREQUEST']._serialized_end=39081 + _globals['_FEERATESREQUEST_FEERATESSTYLE']._serialized_start=39044 + _globals['_FEERATESREQUEST_FEERATESSTYLE']._serialized_end=39081 + _globals['_FEERATESRESPONSE']._serialized_start=39084 + _globals['_FEERATESRESPONSE']._serialized_end=39368 + _globals['_FEERATESPERKB']._serialized_start=39371 + _globals['_FEERATESPERKB']._serialized_end=39838 + _globals['_FEERATESPERKBESTIMATES']._serialized_start=39841 + _globals['_FEERATESPERKBESTIMATES']._serialized_end=39991 + _globals['_FEERATESPERKW']._serialized_start=39994 + _globals['_FEERATESPERKW']._serialized_end=40461 + _globals['_FEERATESPERKWESTIMATES']._serialized_start=40464 + _globals['_FEERATESPERKWESTIMATES']._serialized_end=40614 + _globals['_FEERATESONCHAIN_FEE_ESTIMATES']._serialized_start=40617 + _globals['_FEERATESONCHAIN_FEE_ESTIMATES']._serialized_end=40900 + _globals['_FETCHINVOICEREQUEST']._serialized_start=40903 + _globals['_FETCHINVOICEREQUEST']._serialized_end=41264 + _globals['_FETCHINVOICERESPONSE']._serialized_start=41267 + _globals['_FETCHINVOICERESPONSE']._serialized_end=41421 + _globals['_FETCHINVOICECHANGES']._serialized_start=41424 + _globals['_FETCHINVOICECHANGES']._serialized_end=41682 + _globals['_FETCHINVOICENEXT_PERIOD']._serialized_start=41684 + _globals['_FETCHINVOICENEXT_PERIOD']._serialized_end=41810 + _globals['_FUNDCHANNELREQUEST']._serialized_start=41813 + _globals['_FUNDCHANNELREQUEST']._serialized_end=42320 + _globals['_FUNDCHANNELRESPONSE']._serialized_start=42323 + _globals['_FUNDCHANNELRESPONSE']._serialized_end=42552 + _globals['_FUNDCHANNELCHANNEL_TYPE']._serialized_start=42554 + _globals['_FUNDCHANNELCHANNEL_TYPE']._serialized_end=42630 + _globals['_GETROUTEREQUEST']._serialized_start=42633 + _globals['_GETROUTEREQUEST']._serialized_end=42869 + _globals['_GETROUTERESPONSE']._serialized_start=42871 + _globals['_GETROUTERESPONSE']._serialized_end=42924 + _globals['_GETROUTEROUTE']._serialized_start=42927 + _globals['_GETROUTEROUTE']._serialized_end=43124 + _globals['_GETROUTEROUTE_GETROUTEROUTESTYLE']._serialized_start=43095 + _globals['_GETROUTEROUTE_GETROUTEROUTESTYLE']._serialized_end=43124 + _globals['_LISTFORWARDSREQUEST']._serialized_start=43127 + _globals['_LISTFORWARDSREQUEST']._serialized_end=43566 + _globals['_LISTFORWARDSREQUEST_LISTFORWARDSSTATUS']._serialized_start=43371 + _globals['_LISTFORWARDSREQUEST_LISTFORWARDSSTATUS']._serialized_end=43447 + _globals['_LISTFORWARDSREQUEST_LISTFORWARDSINDEX']._serialized_start=43449 + _globals['_LISTFORWARDSREQUEST_LISTFORWARDSINDEX']._serialized_end=43494 + _globals['_LISTFORWARDSRESPONSE']._serialized_start=43568 + _globals['_LISTFORWARDSRESPONSE']._serialized_end=43635 + _globals['_LISTFORWARDSFORWARDS']._serialized_start=43638 + _globals['_LISTFORWARDSFORWARDS']._serialized_end=44336 + _globals['_LISTFORWARDSFORWARDS_LISTFORWARDSFORWARDSSTATUS']._serialized_start=44083 + _globals['_LISTFORWARDSFORWARDS_LISTFORWARDSFORWARDSSTATUS']._serialized_end=44167 + _globals['_LISTFORWARDSFORWARDS_LISTFORWARDSFORWARDSSTYLE']._serialized_start=44169 + _globals['_LISTFORWARDSFORWARDS_LISTFORWARDSFORWARDSSTYLE']._serialized_end=44217 + _globals['_LISTPAYSREQUEST']._serialized_start=44339 + _globals['_LISTPAYSREQUEST']._serialized_end=44558 + _globals['_LISTPAYSREQUEST_LISTPAYSSTATUS']._serialized_start=44464 + _globals['_LISTPAYSREQUEST_LISTPAYSSTATUS']._serialized_end=44519 + _globals['_LISTPAYSRESPONSE']._serialized_start=44560 + _globals['_LISTPAYSRESPONSE']._serialized_end=44611 + _globals['_LISTPAYSPAYS']._serialized_start=44614 + _globals['_LISTPAYSPAYS']._serialized_end=45253 + _globals['_LISTPAYSPAYS_LISTPAYSPAYSSTATUS']._serialized_start=45028 + _globals['_LISTPAYSPAYS_LISTPAYSPAYSSTATUS']._serialized_end=45087 + _globals['_LISTHTLCSREQUEST']._serialized_start=45255 + _globals['_LISTHTLCSREQUEST']._serialized_end=45297 + _globals['_LISTHTLCSRESPONSE']._serialized_start=45299 + _globals['_LISTHTLCSRESPONSE']._serialized_end=45354 + _globals['_LISTHTLCSHTLCS']._serialized_start=45357 + _globals['_LISTHTLCSHTLCS']._serialized_end=45622 + _globals['_LISTHTLCSHTLCS_LISTHTLCSHTLCSDIRECTION']._serialized_start=45580 + _globals['_LISTHTLCSHTLCS_LISTHTLCSHTLCSDIRECTION']._serialized_end=45622 + _globals['_PINGREQUEST']._serialized_start=45624 + _globals['_PINGREQUEST']._serialized_end=45713 + _globals['_PINGRESPONSE']._serialized_start=45715 + _globals['_PINGRESPONSE']._serialized_end=45745 + _globals['_SENDCUSTOMMSGREQUEST']._serialized_start=45747 + _globals['_SENDCUSTOMMSGREQUEST']._serialized_end=45799 + _globals['_SENDCUSTOMMSGRESPONSE']._serialized_start=45801 + _globals['_SENDCUSTOMMSGRESPONSE']._serialized_end=45840 + _globals['_SETCHANNELREQUEST']._serialized_start=45843 + _globals['_SETCHANNELREQUEST']._serialized_end=46141 + _globals['_SETCHANNELRESPONSE']._serialized_start=46143 + _globals['_SETCHANNELRESPONSE']._serialized_end=46206 + _globals['_SETCHANNELCHANNELS']._serialized_start=46209 + _globals['_SETCHANNELCHANNELS']._serialized_end=46667 + _globals['_SIGNINVOICEREQUEST']._serialized_start=46669 + _globals['_SIGNINVOICEREQUEST']._serialized_end=46708 + _globals['_SIGNINVOICERESPONSE']._serialized_start=46710 + _globals['_SIGNINVOICERESPONSE']._serialized_end=46747 + _globals['_SIGNMESSAGEREQUEST']._serialized_start=46749 + _globals['_SIGNMESSAGEREQUEST']._serialized_end=46786 + _globals['_SIGNMESSAGERESPONSE']._serialized_start=46788 + _globals['_SIGNMESSAGERESPONSE']._serialized_end=46858 + _globals['_WAITBLOCKHEIGHTREQUEST']._serialized_start=46860 + _globals['_WAITBLOCKHEIGHTREQUEST']._serialized_end=46939 + _globals['_WAITBLOCKHEIGHTRESPONSE']._serialized_start=46941 + _globals['_WAITBLOCKHEIGHTRESPONSE']._serialized_end=46987 + _globals['_WAITREQUEST']._serialized_start=46990 + _globals['_WAITREQUEST']._serialized_end=47239 + _globals['_WAITREQUEST_WAITSUBSYSTEM']._serialized_start=47126 + _globals['_WAITREQUEST_WAITSUBSYSTEM']._serialized_end=47183 + _globals['_WAITREQUEST_WAITINDEXNAME']._serialized_start=47185 + _globals['_WAITREQUEST_WAITINDEXNAME']._serialized_end=47239 + _globals['_WAITRESPONSE']._serialized_start=47242 + _globals['_WAITRESPONSE']._serialized_end=47469 + _globals['_WAITRESPONSE_WAITSUBSYSTEM']._serialized_start=47126 + _globals['_WAITRESPONSE_WAITSUBSYSTEM']._serialized_end=47183 + _globals['_STOPREQUEST']._serialized_start=47471 + _globals['_STOPREQUEST']._serialized_end=47484 + _globals['_STOPRESPONSE']._serialized_start=47486 + _globals['_STOPRESPONSE']._serialized_end=47500 + _globals['_PREAPPROVEKEYSENDREQUEST']._serialized_start=47503 + _globals['_PREAPPROVEKEYSENDREQUEST']._serialized_end=47670 + _globals['_PREAPPROVEKEYSENDRESPONSE']._serialized_start=47672 + _globals['_PREAPPROVEKEYSENDRESPONSE']._serialized_end=47699 + _globals['_PREAPPROVEINVOICEREQUEST']._serialized_start=47701 + _globals['_PREAPPROVEINVOICEREQUEST']._serialized_end=47759 + _globals['_PREAPPROVEINVOICERESPONSE']._serialized_start=47761 + _globals['_PREAPPROVEINVOICERESPONSE']._serialized_end=47788 + _globals['_STATICBACKUPREQUEST']._serialized_start=47790 + _globals['_STATICBACKUPREQUEST']._serialized_end=47811 + _globals['_STATICBACKUPRESPONSE']._serialized_start=47813 + _globals['_STATICBACKUPRESPONSE']._serialized_end=47848 + _globals['_NODE']._serialized_start=47851 + _globals['_NODE']._serialized_end=51853 # @@protoc_insertion_point(module_scope) diff --git a/contrib/pyln-testing/pyln/testing/grpc2py.py b/contrib/pyln-testing/pyln/testing/grpc2py.py index 085c55467b8e..2be511d0070b 100644 --- a/contrib/pyln-testing/pyln/testing/grpc2py.py +++ b/contrib/pyln-testing/pyln/testing/grpc2py.py @@ -918,6 +918,7 @@ def listpeerchannels_channels2py(m): "out_offered_msat": amount2msat(m.out_offered_msat), # PrimitiveField in generate_composite "out_payments_fulfilled": m.out_payments_fulfilled, # PrimitiveField in generate_composite "out_fulfilled_msat": amount2msat(m.out_fulfilled_msat), # PrimitiveField in generate_composite + "last_stable_connection": m.last_stable_connection, # PrimitiveField in generate_composite "htlcs": [listpeerchannels_channels_htlcs2py(i) for i in m.htlcs], # ArrayField[composite] in generate_composite "close_to_addr": m.close_to_addr, # PrimitiveField in generate_composite }) @@ -967,6 +968,7 @@ def listclosedchannels_closedchannels2py(m): "last_commitment_txid": hexlify(m.last_commitment_txid), # PrimitiveField in generate_composite "last_commitment_fee_msat": amount2msat(m.last_commitment_fee_msat), # PrimitiveField in generate_composite "close_cause": str(m.close_cause), # EnumField in generate_composite + "last_stable_connection": m.last_stable_connection, # PrimitiveField in generate_composite }) diff --git a/devtools/dump-gossipstore.c b/devtools/dump-gossipstore.c index 3df77a92682e..09c6f3a1e428 100644 --- a/devtools/dump-gossipstore.c +++ b/devtools/dump-gossipstore.c @@ -113,12 +113,12 @@ int main(int argc, char *argv[]) printf("t=%u node_announcement: %s\n", be32_to_cpu(hdr.timestamp), tal_hex(msg, msg)); - } else if (fromwire_gossip_store_private_channel(msg, msg, &sat, + } else if (fromwire_gossip_store_private_channel_obs(msg, msg, &sat, &inner)) { printf("private channel_announcement: %s %s\n", type_to_string(tmpctx, struct amount_sat, &sat), tal_hex(msg, inner)); - } else if (fromwire_gossip_store_private_update(msg, msg, + } else if (fromwire_gossip_store_private_update_obs(msg, msg, &inner)) { printf("private channel_update: %s\n", tal_hex(msg, inner)); diff --git a/doc/lightning-listclosedchannels.7.md b/doc/lightning-listclosedchannels.7.md index 182790cfc0af..31503aee2a1e 100644 --- a/doc/lightning-listclosedchannels.7.md +++ b/doc/lightning-listclosedchannels.7.md @@ -53,6 +53,7 @@ On success, an object containing **closedchannels** is returned. It is an array - **funding\_pushed\_msat** (msat, optional): How much `opener` pushed immediate (if non-zero) - **last\_commitment\_txid** (hash, optional): The final commitment tx's txid (or mutual close, if we accepted it). Not present for some very old, small channels pre-0.7.0. - **last\_commitment\_fee\_msat** (msat, optional): The fee on `last_commitment_txid` +- **last\_stable\_connection** (u64, optional): Last time we reestablished the open channel and stayed connected for 1 minute *(added v24.02)* [comment]: # (GENERATE-FROM-SCHEMA-END) @@ -76,4 +77,4 @@ RESOURCES Main web site: Lightning -[comment]: # ( SHA256STAMP:1437321ab48ffcf8c5aa437db53eef72f5ed62dd1da7900483c86482e533a461) +[comment]: # ( SHA256STAMP:559d917217fe6d765d8bf019e46bf03d37dae9a437e530b1456252bcb901cbc9) diff --git a/doc/lightning-listpeerchannels.7.md b/doc/lightning-listpeerchannels.7.md index a3c3bc0b6174..8efacfc329ae 100644 --- a/doc/lightning-listpeerchannels.7.md +++ b/doc/lightning-listpeerchannels.7.md @@ -116,6 +116,7 @@ On success, an object containing **channels** is returned. It is an array of ob - **out\_offered\_msat** (msat, optional): Total amount of outgoing payment attempts - **out\_payments\_fulfilled** (u64, optional): Number of successful outgoing payment attempts - **out\_fulfilled\_msat** (msat, optional): Total amount of successful outgoing payment attempts +- **last\_stable\_connection** (u64, optional): Last time we reestablished the open channel and stayed connected for 1 minute *(added v24.02)* - **htlcs** (array of objects, optional): current HTLCs in this channel: - **direction** (string): Whether it came from peer, or is going to peer (one of "in", "out") - **id** (u64): Unique ID for this htlc on this channel in this direction @@ -133,6 +134,10 @@ On success, an object containing **channels** is returned. It is an array of ob - **state** (string): Status of the HTLC (one of "RCVD\_ADD\_HTLC", "RCVD\_ADD\_COMMIT", "SENT\_ADD\_REVOCATION", "SENT\_ADD\_ACK\_COMMIT", "RCVD\_ADD\_ACK\_REVOCATION", "SENT\_REMOVE\_HTLC", "SENT\_REMOVE\_COMMIT", "RCVD\_REMOVE\_REVOCATION", "RCVD\_REMOVE\_ACK\_COMMIT", "SENT\_REMOVE\_ACK\_REVOCATION") +If **peer\_connected** is *true*: + + - **reestablished** (boolean, optional): True if we have successfully exchanged reestablish messages this connection + If **close\_to** is present: - **close\_to\_addr** (string, optional): The bitcoin address we will close to (present if close\_to\_addr is a standardized address) @@ -215,4 +220,4 @@ Main web site: Lightning RFC site (BOLT \#9): -[comment]: # ( SHA256STAMP:a7fc3b30593a04b6b04c1516aeb2039f6ab4e29cf12f81b306a8a068273c3604) +[comment]: # ( SHA256STAMP:c2ab91a2357b83264415f923b9d5195e5294a17b7424d9e75ac9ea704bea8fc5) diff --git a/doc/lightning-sql.7.md b/doc/lightning-sql.7.md index dd2aef8d2d98..6c3afd714696 100644 --- a/doc/lightning-sql.7.md +++ b/doc/lightning-sql.7.md @@ -169,6 +169,7 @@ The following tables are currently supported: - `last_commitment_txid` (type `hash`, sqltype `BLOB`) - `last_commitment_fee_msat` (type `msat`, sqltype `INTEGER`) - `close_cause` (type `string`, sqltype `TEXT`) + - `last_stable_connection` (type `u64`, sqltype `INTEGER`) - `forwards` indexed by `in_channel and in_htlc_id` (see lightning-listforwards(7)) - `created_index` (type `u64`, sqltype `INTEGER`) @@ -341,6 +342,7 @@ The following tables are currently supported: - `out_offered_msat` (type `msat`, sqltype `INTEGER`) - `out_payments_fulfilled` (type `u64`, sqltype `INTEGER`) - `out_fulfilled_msat` (type `msat`, sqltype `INTEGER`) + - `last_stable_connection` (type `u64`, sqltype `INTEGER`) - related table `peerchannels_htlcs` - `row` (reference to `peerchannels.rowid`, sqltype `INTEGER`) - `arrindex` (index within array, sqltype `INTEGER`) @@ -352,6 +354,7 @@ The following tables are currently supported: - `local_trimmed` (type `boolean`, sqltype `INTEGER`) - `status` (type `string`, sqltype `TEXT`) - `state` (type `string`, sqltype `TEXT`) + - `reestablished` (type `boolean`, sqltype `INTEGER`) - `close_to_addr` (type `string`, sqltype `TEXT`) - `last_tx_fee_msat` (type `msat`, sqltype `INTEGER`) - `direction` (type `u32`, sqltype `INTEGER`) @@ -530,4 +533,4 @@ RESOURCES --------- Main web site: -[comment]: # ( SHA256STAMP:5c5e14f8fde75b877080c0c10feb786f1d2fefbb61a62aecb8d003d1d54627e9) +[comment]: # ( SHA256STAMP:299446e88b1f847a82ae63c2087ce28a36b7c8fea2b102d4e3d87c420a9268e9) diff --git a/doc/schemas/listclosedchannels.schema.json b/doc/schemas/listclosedchannels.schema.json index b090bf2cbcc0..25bb800893c5 100644 --- a/doc/schemas/listclosedchannels.schema.json +++ b/doc/schemas/listclosedchannels.schema.json @@ -180,6 +180,11 @@ "onchain" ], "description": "What caused the channel to close" + }, + "last_stable_connection": { + "type": "u64", + "added": "v24.02", + "description": "Last time we reestablished the open channel and stayed connected for 1 minute" } } } diff --git a/doc/schemas/listpeerchannels.schema.json b/doc/schemas/listpeerchannels.schema.json index e731f6c2cc21..9e27aea18886 100644 --- a/doc/schemas/listpeerchannels.schema.json +++ b/doc/schemas/listpeerchannels.schema.json @@ -28,6 +28,7 @@ "type": "boolean", "description": "A boolean flag that is set to true if the peer is online" }, + "reestablished": {}, "state": { "type": "string", "enum": [ @@ -555,6 +556,11 @@ "type": "msat", "description": "Total amount of successful outgoing payment attempts" }, + "last_stable_connection": { + "type": "u64", + "added": "v24.02", + "description": "Last time we reestablished the open channel and stayed connected for 1 minute" + }, "htlcs": { "type": "array", "description": "current HTLCs in this channel", @@ -634,6 +640,7 @@ "alias": {}, "peer_id": {}, "peer_connected": {}, + "reestablished": {}, "state": { "type": "string", "enum": [ @@ -679,6 +686,7 @@ "status": {}, "peer_id": {}, "peer_connected": {}, + "reestablished": {}, "state": { "type": "string", "enum": [ @@ -703,6 +711,26 @@ } }, "allOf": [ + { + "if": { + "properties": { + "peer_connected": { + "type": "boolean", + "enum": [ + true + ] + } + } + }, + "then": { + "properties": { + "reestablished": { + "type": "boolean", + "description": "True if we have successfully exchanged reestablish messages this connection" + } + } + } + }, { "if": { "required": [ @@ -716,6 +744,7 @@ "state": {}, "peer_id": {}, "peer_connected": {}, + "reestablished": {}, "scratch_txid": {}, "channel_type": {}, "feerate": {}, @@ -778,6 +807,7 @@ "out_payments_fulfilled": {}, "out_fulfilled_msat": {}, "out_msatoshi_fulfilled": {}, + "last_stable_connection": {}, "htlcs": {}, "initial_feerate": {}, "last_feerate": {}, @@ -807,6 +837,7 @@ "state": {}, "peer_id": {}, "peer_connected": {}, + "reestablished": {}, "alias": {}, "scratch_txid": {}, "channel_type": {}, @@ -870,6 +901,7 @@ "out_payments_fulfilled": {}, "out_fulfilled_msat": {}, "out_msatoshi_fulfilled": {}, + "last_stable_connection": {}, "htlcs": {}, "initial_feerate": {}, "last_feerate": {}, @@ -898,6 +930,7 @@ "alias": {}, "peer_id": {}, "peer_connected": {}, + "reestablished": {}, "state": {}, "scratch_txid": {}, "channel_type": {}, @@ -961,6 +994,7 @@ "out_payments_fulfilled": {}, "out_fulfilled_msat": {}, "out_msatoshi_fulfilled": {}, + "last_stable_connection": {}, "htlcs": {}, "initial_feerate": {}, "last_feerate": {}, @@ -991,6 +1025,7 @@ "state": {}, "peer_id": {}, "peer_connected": {}, + "reestablished": {}, "scratch_txid": {}, "channel_type": {}, "feerate": {}, @@ -1053,6 +1088,7 @@ "out_payments_fulfilled": {}, "out_fulfilled_msat": {}, "out_msatoshi_fulfilled": {}, + "last_stable_connection": {}, "htlcs": {}, "inflight": {}, "close_to_addr": {}, diff --git a/external/Makefile b/external/Makefile index 2767cc06885d..e199108bf0c1 100644 --- a/external/Makefile +++ b/external/Makefile @@ -3,8 +3,7 @@ SUBMODULES = \ external/libwally-core \ external/gheap \ external/jsmn \ - external/libbacktrace \ - external/lnprototest + external/libbacktrace ifeq ($(HAVE_LOWDOWN),0) SUBMODULES += external/lowdown diff --git a/external/lnprototest b/external/lnprototest deleted file mode 160000 index a8d4dcf6b859..000000000000 --- a/external/lnprototest +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a8d4dcf6b859f3c11c92a917f7c48b2051dbb4c4 diff --git a/gossipd/Makefile b/gossipd/Makefile index c393de6a3950..42e79f256963 100644 --- a/gossipd/Makefile +++ b/gossipd/Makefile @@ -6,7 +6,6 @@ GOSSIPD_HEADERS_WSRC := gossipd/gossipd_wiregen.h \ gossipd/gossipd.h \ gossipd/gossip_store.h \ gossipd/queries.h \ - gossipd/gossip_generation.h \ gossipd/routing.h \ gossipd/seeker.h GOSSIPD_HEADERS := $(GOSSIPD_HEADERS_WSRC) gossipd/broadcast.h @@ -54,7 +53,6 @@ GOSSIPD_COMMON_OBJS := \ common/ping.o \ common/psbt_open.o \ common/pseudorand.o \ - common/private_channel_announcement.o \ common/random_select.o \ common/setup.o \ common/status.o \ diff --git a/gossipd/gossip_generation.c b/gossipd/gossip_generation.c deleted file mode 100644 index 84532bc19218..000000000000 --- a/gossipd/gossip_generation.c +++ /dev/null @@ -1,960 +0,0 @@ -/* Routines to make our own gossip messages. Not as in "we're the gossip - * generation, man!" */ -#include "config.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Create a node_announcement with the given signature. It may be NULL in the - * case we need to create a provisional announcement for the HSM to sign. - * This is called twice: once with the dummy signature to get it signed and a - * second time to build the full packet with the signature. The timestamp is - * handed in rather than using time_now() internally, since that could change - * 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, - const struct lease_rates *rates) -{ - struct wireaddr *was; - u8 *addresses = tal_arr(tmpctx, u8, 0); - u8 *announcement; - struct tlv_node_ann_tlvs *na_tlv; - size_t i, count_announceable; - - /* add all announceable addresses */ - count_announceable = tal_count(daemon->announceable); - was = tal_arr(tmpctx, struct wireaddr, 0); - for (i = 0; i < count_announceable; i++) - tal_arr_expand(&was, daemon->announceable[i]); - - /* Add discovered IPs v4/v6 verified by peer `remote_addr` feature. */ - /* Only do that if we don't have any addresses announced or - * `config.ip_discovery` is explicitly enabled. */ - if ((daemon->ip_discovery == OPT_AUTOBOOL_AUTO && count_announceable == 0) || - daemon->ip_discovery == OPT_AUTOBOOL_TRUE) { - if (daemon->discovered_ip_v4 != NULL && - !wireaddr_arr_contains(was, daemon->discovered_ip_v4)) - tal_arr_expand(&was, *daemon->discovered_ip_v4); - if (daemon->discovered_ip_v6 != NULL && - !wireaddr_arr_contains(was, daemon->discovered_ip_v6)) - tal_arr_expand(&was, *daemon->discovered_ip_v6); - } - - /* Sort by address type again, as we added dynamic discovered_ip v4/v6. */ - /* BOLT #7: - * - * The origin node: - *... - * - MUST place address descriptors in ascending order. - */ - asort(was, tal_count(was), wireaddr_cmp_type, NULL); - - if (!sig) - sig = talz(tmpctx, secp256k1_ecdsa_signature); - - for (i = 0; i < tal_count(was); i++) - towire_wireaddr(&addresses, &was[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[NODE_ANNOUNCE_FEATURE], - timestamp, - &daemon->id, daemon->rgb, daemon->alias, - addresses, - na_tlv); - return announcement; -} - -/* Helper to get non-signature, non-timestamp parts of (valid!) channel_update */ -void get_cupdate_parts(const u8 *channel_update, - const u8 *parts[2], - size_t sizes[2]) -{ - /* BOLT #7: - * - * 1. type: 258 (`channel_update`) - * 2. data: - * * [`signature`:`signature`] - * * [`chain_hash`:`chain_hash`] - * * [`short_channel_id`:`short_channel_id`] - * * [`u32`:`timestamp`] - *... - */ - /* Note: 2 bytes for `type` field */ - /* We already checked it's valid before accepting */ - assert(tal_count(channel_update) > 2 + 64 + 32 + 8 + 4); - parts[0] = channel_update + 2 + 64; - sizes[0] = 32 + 8; - parts[1] = channel_update + 2 + 64 + 32 + 8 + 4; - sizes[1] = tal_count(channel_update) - (64 + 2 + 32 + 8 + 4); -} - -/* Is this channel_update different from prev (not sigs and timestamps)? */ -bool cupdate_different(struct gossip_store *gs, - const struct half_chan *hc, - const u8 *cupdate) -{ - const u8 *oparts[2], *nparts[2]; - size_t osizes[2], nsizes[2]; - const u8 *orig; - - /* Get last one we have. */ - orig = gossip_store_get(tmpctx, gs, hc->bcast.index); - get_cupdate_parts(orig, oparts, osizes); - get_cupdate_parts(cupdate, nparts, nsizes); - - return !memeq(oparts[0], osizes[0], nparts[0], nsizes[0]) - || !memeq(oparts[1], osizes[1], nparts[1], nsizes[1]); -} - -/* 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[3], - size_t sizes[3]) -{ - size_t len, ad_len; - const u8 *flen, *ad_start; - - /* BOLT #7: - * - * 1. type: 257 (`node_announcement`) - * 2. data: - * * [`signature`:`signature`] - * * [`u16`:`flen`] - * * [`flen*byte`:`features`] - * * [`u32`:`timestamp`] - *... - */ - /* Note: 2 bytes for `type` field */ - /* We already checked it's valid before accepting */ - assert(tal_count(node_announcement) > 2 + 64); - parts[0] = node_announcement + 2 + 64; - - /* Read flen to get size */ - flen = parts[0]; - len = tal_count(node_announcement) - (2 + 64); - 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; - - /* 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, - bool *only_missing_tlv) -{ - const u8 *oparts[3], *nparts[3]; - size_t osizes[3], nsizes[3]; - const u8 *orig; - - /* Get last one we have. */ - orig = gossip_store_get(tmpctx, gs, node->bcast.index); - 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[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)); -} - - -/* Mutual recursion via timer */ -static void update_own_node_announcement_after_startup(struct daemon *daemon); -static void setup_force_nannounce_regen_timer(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, - bool startup, - bool always_refresh) -{ - u32 timestamp = gossip_time_now(daemon->rstate).ts.tv_sec; - u8 *nannounce; - struct node *self = get_node(daemon->rstate, &daemon->id); - - /* If we don't have any channels now, don't send node_announcement */ - if (!self || !node_has_broadcastable_channels(self)) - goto reset_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; - bool only_missing_tlv; - - if (!nannounce_different(daemon->rstate->gs, self, nannounce, - &only_missing_tlv)) { - if (always_refresh) - goto send; - /* Update if old announcement is at least 7 days old. */ - if (timestamp > self->bcast.timestamp && - timestamp - self->bcast.timestamp > - GOSSIP_PRUNE_INTERVAL(daemon->rstate->dev_fast_gossip_prune) / 2) - goto send; - /* First time? Start regen timer. */ - if (!daemon->node_announce_regen_timer) - goto reset_timer; - return; - } - - /* Missing liquidity_ad, maybe we'll get plugin callback */ - 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); - - /* Discard existing timer. */ - daemon->node_announce_timer - = tal_free(daemon->node_announce_timer); - daemon->node_announce_timer - = new_reltimer(&daemon->timers, - daemon, - time_from_sec(delay), - update_own_node_announcement_after_startup, - 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); - - /* Discard existing timer. */ - daemon->node_announce_timer - = tal_free(daemon->node_announce_timer); - daemon->node_announce_timer - = new_reltimer(&daemon->timers, - daemon, - time_from_sec(next - timestamp), - update_own_node_announcement_after_startup, - daemon); - return; - } - } - -send: - sign_and_send_nannounce(daemon, nannounce, timestamp); - -reset_timer: - /* Generate another one in 24 hours. */ - setup_force_nannounce_regen_timer(daemon); - - return; -} - -static void update_own_node_announcement_after_startup(struct daemon *daemon) -{ - update_own_node_announcement(daemon, false, false); -} - -/* This creates and transmits a *new* node announcement */ -static void force_self_nannounce_regen(struct daemon *daemon) -{ - update_own_node_announcement(daemon, false, true); -} - -/* Because node_announcement propagation is spotty, we regenerate this every - * 24 hours. */ -static void setup_force_nannounce_regen_timer(struct daemon *daemon) -{ - struct timerel regen_time; - - /* For developers we can force a regen every 24 seconds to test */ - if (daemon->rstate->dev_fast_gossip_prune) - regen_time = time_from_sec(24); - else - regen_time = time_from_sec(24 * 3600); - - tal_free(daemon->node_announce_regen_timer); - daemon->node_announce_regen_timer - = new_reltimer(&daemon->timers, - daemon, - regen_time, - force_self_nannounce_regen, - daemon); -} - - -/* Should we announce our own node? Called at strategic places. */ -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 - * callback, but when we start up we don't want to make multiple - * announcments, so we use this approach for now. */ - if (!daemon->rstate->local_channel_announced) - return; - - update_own_node_announcement(daemon, startup, false); -} - -/* Fast accessors for channel_update fields */ -static u8 *channel_flags_access(const u8 *channel_update) -{ - /* BOLT #7: - * 1. type: 258 (`channel_update`) - * 2. data: - * * [`signature`:`signature`] - * * [`chain_hash`:`chain_hash`] - * * [`short_channel_id`:`short_channel_id`] - * * [`u32`:`timestamp`] - * * [`byte`:`message_flags`] - * * [`byte`:`channel_flags`] - */ - /* Note: 2 bytes for `type` field */ - return cast_const(u8 *, &channel_update[2 + 64 + 32 + 8 + 4 + 1]); -} - -static u8 *timestamp_access(const u8 *channel_update) -{ - /* BOLT #7: - * 1. type: 258 (`channel_update`) - * 2. data: - * * [`signature`:`signature`] - * * [`chain_hash`:`chain_hash`] - * * [`short_channel_id`:`short_channel_id`] - * * [`u32`:`timestamp`] - * * [`byte`:`message_flags`] - * * [`byte`:`channel_flags`] - */ - /* Note: 2 bytes for `type` field */ - return cast_const(u8 *, &channel_update[2 + 64 + 32 + 8]); -} - -static bool is_disabled(const u8 *channel_update) -{ - return *channel_flags_access(channel_update) & ROUTING_FLAGS_DISABLED; -} - -static bool is_enabled(const u8 *channel_update) -{ - return !is_disabled(channel_update); -} - - -static u32 timestamp_for_update(struct daemon *daemon, - const u32 *prev_timestamp, - bool disable) -{ - u32 timestamp = gossip_time_now(daemon->rstate).ts.tv_sec; - - /* Create an unsigned channel_update: we backdate enables, so - * we can always send a disable in an emergency. */ - if (!disable) - timestamp -= GOSSIP_MIN_INTERVAL(daemon->rstate->dev_fast_gossip); - - if (prev_timestamp) { - /* Timestamps can't go backwards! */ - if (timestamp < *prev_timestamp) - timestamp = *prev_timestamp + 1; - - /* If we ever use set-based propagation, ensuring the toggle - * the lower bit in consecutive timestamps makes it more - * robust. */ - if ((timestamp & 1) == (*prev_timestamp & 1)) - timestamp++; - } - - return timestamp; -} - -static u8 *sign_and_timestamp_update(const tal_t *ctx, - struct daemon *daemon, - const struct chan *chan, - int direction, - u8 *unsigned_update TAKES) -{ - u8 *msg, *update; - be32 timestamp; - const u32 *prev_timestamp; - const struct half_chan *hc = &chan->half[direction]; - - if (is_halfchan_defined(hc)) - prev_timestamp = &hc->bcast.timestamp; - else - prev_timestamp = NULL; - - /* Get an appropriate timestamp */ - timestamp = cpu_to_be32(timestamp_for_update(daemon, - prev_timestamp, - is_disabled(unsigned_update))); - memcpy(timestamp_access(unsigned_update), ×tamp, sizeof(timestamp)); - - /* Note that we treat the hsmd as synchronous. This is simple (no - * callback hell)!, but may need to change to async if we ever want - * remote HSMs */ - if (!wire_sync_write(HSM_FD, - towire_hsmd_cupdate_sig_req(tmpctx, unsigned_update))) { - status_failed(STATUS_FAIL_HSM_IO, "Writing cupdate_sig_req: %s", - strerror(errno)); - } - - msg = wire_sync_read(tmpctx, HSM_FD); - if (!msg || !fromwire_hsmd_cupdate_sig_reply(ctx, msg, &update)) { - status_failed(STATUS_FAIL_HSM_IO, - "Reading cupdate_sig_req: %s", - strerror(errno)); - } - - if (taken(unsigned_update)) - tal_free(unsigned_update); - - /* Tell lightningd about this immediately (even if we're not actually - * applying it now). We choose not to send info about private - * channels, even in errors. */ - if (is_chan_public(chan)) { - msg = towire_gossipd_got_local_channel_update(NULL, &chan->scid, - update); - daemon_conn_send(daemon->master, take(msg)); - } - - return update; -} - -static u8 *create_unsigned_update(const tal_t *ctx, - const struct short_channel_id *scid, - int direction, - bool enable, - u16 cltv_expiry_delta, - struct amount_msat htlc_minimum, - struct amount_msat htlc_maximum, - u32 fee_base_msat, - u32 fee_proportional_millionths, - bool public) -{ - secp256k1_ecdsa_signature dummy_sig; - u8 message_flags, channel_flags; - - /* So valgrind doesn't complain */ - memset(&dummy_sig, 0, sizeof(dummy_sig)); - - /* BOLT-f3a9f7f4e9e7a5a2997f3129e13d94090091846a #7: - * - * The `channel_flags` bitfield is used to indicate the direction of - * the channel: it identifies the node that this update originated - * from and signals various options concerning the channel. The - * following table specifies the meaning of its individual bits: - * - * | Bit Position | Name | Meaning | - * | ------------- | ----------- | -------------------------------- | - * | 0 | `direction` | Direction this update refers to. | - * | 1 | `disable` | Disable the channel. | - */ - channel_flags = direction; - if (!enable) - channel_flags |= ROUTING_FLAGS_DISABLED; - - /* BOLT #7: - * - * The `message_flags` bitfield is used to provide additional - * details about the message: - * - * | Bit Position | Name | - * | ------------- | ---------------| - * | 0 | `must_be_one` | - * | 1 | `dont_forward` | - */ - message_flags = ROUTING_OPT_HTLC_MAX_MSAT; - if (!public) - message_flags |= ROUTING_OPT_DONT_FORWARD; - - /* We create an update with a dummy signature and timestamp. */ - return towire_channel_update(ctx, - &dummy_sig, /* sig set later */ - &chainparams->genesis_blockhash, - scid, - 0, /* timestamp set later */ - message_flags, channel_flags, - cltv_expiry_delta, - htlc_minimum, - fee_base_msat, - fee_proportional_millionths, - htlc_maximum); -} - -static void apply_update(struct daemon *daemon, - const struct chan *chan, - int direction, - u8 *update TAKES) -{ - u8 *msg; - struct peer *peer = find_peer(daemon, &chan->nodes[!direction]->id); - - if (!is_chan_public(chan)) { - /* Save and restore taken state, for handle_channel_update */ - bool update_taken = taken(update); - - /* handle_channel_update will not put private updates in the - * broadcast list, but we send it direct to the peer (if we - * have one connected) now */ - if (peer) - queue_peer_msg(peer, update); - - if (update_taken) - take(update); - } - - msg = handle_channel_update(daemon->rstate, update, NULL, NULL, true); - if (msg) - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "%s: rejected local channel update %s: %s", - __func__, - /* Normally we must not touch something taken() - * but we're in deep trouble anyway, and - * handle_channel_update only tal_steals onto - * tmpctx, so it's actually OK. */ - tal_hex(tmpctx, update), - tal_hex(tmpctx, msg)); -} - -static void sign_timestamp_and_apply_update(struct daemon *daemon, - const struct chan *chan, - int direction, - u8 *update TAKES) -{ - update = sign_and_timestamp_update(NULL, daemon, chan, direction, - update); - apply_update(daemon, chan, direction, take(update)); -} - -/* We don't want to thrash the gossip network, so we often defer sending an - * update. We track them here. */ -struct deferred_update { - /* Off daemon->deferred_updates (our leak detection needs this as - * first element in struct, because it's dumb!) */ - struct list_node list; - /* The daemon */ - struct daemon *daemon; - /* Channel it's for (and owner) */ - const struct chan *chan; - int direction; - /* Timer which will fire when it's time to apply. */ - struct oneshot *channel_update_timer; - /* The actual `update_channel` to apply */ - u8 *update; -}; - -static struct deferred_update *find_deferred_update(struct daemon *daemon, - const struct chan *chan) -{ - struct deferred_update *du; - - list_for_each(&daemon->deferred_updates, du, list) { - if (du->chan == chan) - return du; - } - return NULL; -} - -static void destroy_deferred_update(struct deferred_update *du) -{ - list_del(&du->list); -} - -static void apply_deferred_update(struct deferred_update *du) -{ - apply_update(du->daemon, du->chan, du->direction, take(du->update)); - tal_free(du); -} - -static void defer_update(struct daemon *daemon, - u32 delay, - const struct chan *chan, - int direction, - u8 *unsigned_update TAKES) -{ - struct deferred_update *du; - - /* Override any existing one */ - tal_free(find_deferred_update(daemon, chan)); - - /* If chan is gone, so are we. */ - du = tal(chan, struct deferred_update); - du->daemon = daemon; - du->chan = chan; - du->direction = direction; - du->update = sign_and_timestamp_update(du, daemon, chan, direction, - unsigned_update); - if (delay != 0xFFFFFFFF) - du->channel_update_timer = new_reltimer(&daemon->timers, du, - time_from_sec(delay), - apply_deferred_update, - du); - else - du->channel_update_timer = NULL; - list_add_tail(&daemon->deferred_updates, &du->list); - tal_add_destructor(du, destroy_deferred_update); -} - -/* If there is a pending update for this local channel, apply immediately. */ -static bool local_channel_update_latest(struct daemon *daemon, struct chan *chan) -{ - struct deferred_update *du; - - du = find_deferred_update(daemon, chan); - if (!du) - return false; - - /* Frees itself */ - apply_deferred_update(du); - return true; -} - -/* Get previous update. */ -static u8 *prev_update(const tal_t *ctx, - struct daemon *daemon, const struct chan *chan, int direction) -{ - u8 *prev; - - if (!is_halfchan_defined(&chan->half[direction])) - return NULL; - - prev = cast_const(u8 *, - gossip_store_get(tmpctx, daemon->rstate->gs, - chan->half[direction].bcast.index)); - - /* If it's a private update, unwrap */ - if (!fromwire_gossip_store_private_update(ctx, prev, &prev)) - tal_steal(ctx, prev); - return prev; -} - -/* This is a refresh of a local channel (after 13 days). */ -void refresh_local_channel(struct daemon *daemon, - struct chan *chan, int direction) -{ - u16 cltv_expiry_delta; - struct amount_msat htlc_minimum, htlc_maximum; - u32 fee_base_msat, fee_proportional_millionths, timestamp; - u8 *prev, *update; - u8 message_flags, channel_flags; - secp256k1_ecdsa_signature signature; - struct bitcoin_blkid chain_hash; - struct short_channel_id short_channel_id; - - /* If there's a pending update, apply it and we're done. */ - if (local_channel_update_latest(daemon, chan)) - return; - - prev = prev_update(tmpctx, daemon, chan, direction); - if (!prev) - return; - - if (!fromwire_channel_update(prev, - &signature, &chain_hash, - &short_channel_id, ×tamp, - &message_flags, &channel_flags, - &cltv_expiry_delta, - &htlc_minimum, - &fee_base_msat, - &fee_proportional_millionths, - &htlc_maximum)) { - status_broken("Could not decode local channel_update %s!", - tal_hex(tmpctx, prev)); - return; - } - - /* BOLT-f3a9f7f4e9e7a5a2997f3129e13d94090091846a #7: - * - * The `channel_flags` bitfield is used to indicate the direction of - * the channel: it identifies the node that this update originated - * from and signals various options concerning the channel. The - * following table specifies the meaning of its individual bits: - * - * | Bit Position | Name | Meaning | - * | ------------- | ----------- | -------------------------------- | - * | 0 | `direction` | Direction this update refers to. | - * | 1 | `disable` | Disable the channel. | - */ - if (direction != (channel_flags & ROUTING_FLAGS_DIRECTION)) { - status_broken("Wrong channel direction %s!", - tal_hex(tmpctx, prev)); - return; - } - - /* Don't refresh disabled channels. */ - if (channel_flags & ROUTING_FLAGS_DISABLED) - return; - - update = create_unsigned_update(NULL, &short_channel_id, direction, - false, cltv_expiry_delta, - htlc_minimum, htlc_maximum, - fee_base_msat, - fee_proportional_millionths, - !(message_flags & ROUTING_OPT_DONT_FORWARD)); - sign_timestamp_and_apply_update(daemon, chan, direction, take(update)); -} - -/* channeld (via lightningd) asks us to update the local channel. */ -void handle_local_channel_update(struct daemon *daemon, const u8 *msg) -{ - struct node_id id; - struct short_channel_id scid; - bool enable; - u16 cltv_expiry_delta; - struct amount_msat htlc_minimum, htlc_maximum; - u32 fee_base_msat, fee_proportional_millionths; - struct chan *chan; - int direction; - u8 *unsigned_update; - const struct half_chan *hc; - bool public; - - if (!fromwire_gossipd_local_channel_update(msg, - &id, - &scid, - &enable, - &cltv_expiry_delta, - &htlc_minimum, - &fee_base_msat, - &fee_proportional_millionths, - &htlc_maximum, - &public)) { - master_badmsg(WIRE_GOSSIPD_LOCAL_CHANNEL_UPDATE, msg); - } - - chan = get_channel(daemon->rstate, &scid); - /* Can theoretically happen if channel just closed. */ - if (!chan) { - status_peer_debug(&id, "local_channel_update for unknown %s", - type_to_string(tmpctx, struct short_channel_id, - &scid)); - return; - } - - if (!local_direction(daemon->rstate, chan, &direction)) { - status_peer_broken(&id, "bad local_channel_update chan %s", - type_to_string(tmpctx, - struct short_channel_id, - &scid)); - return; - } - - unsigned_update = create_unsigned_update(tmpctx, &scid, direction, - enable, cltv_expiry_delta, - htlc_minimum, htlc_maximum, - fee_base_msat, - fee_proportional_millionths, - public); - - hc = &chan->half[direction]; - - /* Ignore duplicates. */ - if (is_halfchan_defined(hc) - && !cupdate_different(daemon->rstate->gs, hc, unsigned_update)) - return; - - /* Too early? Defer (don't worry if it's unannounced). */ - if (is_halfchan_defined(hc) && is_chan_public(chan)) { - u32 now = time_now().ts.tv_sec; - u32 next_time = hc->bcast.timestamp - + GOSSIP_MIN_INTERVAL(daemon->rstate->dev_fast_gossip); - if (now < next_time) { - defer_update(daemon, next_time - now, - chan, direction, take(unsigned_update)); - return; - } - } - - sign_timestamp_and_apply_update(daemon, chan, direction, - take(unsigned_update)); -} - -/* Take update, set/unset disabled flag (and update timestamp). - */ -static void set_disable_flag(u8 *channel_update, bool disable) -{ - u8 *channel_flags = channel_flags_access(channel_update); - - if (disable) - *channel_flags |= ROUTING_FLAGS_DISABLED; - else - *channel_flags &= ~ROUTING_FLAGS_DISABLED; -} - -/* We don't immediately disable, to avoid flapping. */ -void local_disable_chan(struct daemon *daemon, const struct chan *chan, int direction) -{ - struct deferred_update *du; - u8 *update = prev_update(tmpctx, daemon, chan, direction); - if (!update) - return; - - du = find_deferred_update(daemon, chan); - - /* Will a deferred update disable it already? OK, nothing to do. */ - if (du && is_disabled(du->update)) - return; - - /* OK, we definitely don't want deferred update to re-enable! */ - tal_free(du); - - /* Is it already disabled? */ - if (is_disabled(update)) - return; - - /* This is deferred indefinitely (flushed if needed though) */ - set_disable_flag(update, true); - defer_update(daemon, 0xFFFFFFFF, chan, direction, take(update)); -} - -/* lightningd tells us it used the local channel update. */ -void handle_used_local_channel_update(struct daemon *daemon, const u8 *msg) -{ - struct short_channel_id scid; - struct chan *chan; - - if (!fromwire_gossipd_used_local_channel_update(msg, &scid)) - master_badmsg(WIRE_GOSSIPD_USED_LOCAL_CHANNEL_UPDATE, msg); - - chan = get_channel(daemon->rstate, &scid); - /* Might have closed in meantime, but v unlikely! */ - if (!chan) { - status_broken("used_local_channel_update on unknown %s", - type_to_string(tmpctx, struct short_channel_id, - &scid)); - return; - } - - /* This whole idea is racy: they might have used a *previous* update. - * But that's OK: the notification is an optimization to avoid - * broadcasting updates we never use (route flapping). In this case, - * we might broadcast a more recent update than the one we sent to a - * peer. */ - local_channel_update_latest(daemon, chan); -} - -void local_enable_chan(struct daemon *daemon, const struct chan *chan, int direction) -{ - struct deferred_update *du; - u8 *update = prev_update(tmpctx, daemon, chan, direction); - - - if (!update) - return; - - du = find_deferred_update(daemon, chan); - - /* Will a deferred update enable it? If so, apply immediately. */ - if (du && is_enabled(du->update)) { - apply_deferred_update(du); - return; - } - - /* OK, we definitely don't want deferred update to disable! */ - tal_free(du); - - /* Is it already enabled? */ - if (is_enabled(update)) - return; - - /* Apply this enabling update immediately. */ - set_disable_flag(update, false); - sign_timestamp_and_apply_update(daemon, chan, direction, take(update)); -} diff --git a/gossipd/gossip_generation.h b/gossipd/gossip_generation.h deleted file mode 100644 index b39cc158b47f..000000000000 --- a/gossipd/gossip_generation.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef LIGHTNING_GOSSIPD_GOSSIP_GENERATION_H -#define LIGHTNING_GOSSIPD_GOSSIP_GENERATION_H -#include "config.h" -#include -#include -#include - -struct chan; -struct daemon; -struct half_chan; -struct local_chan; -struct gossip_store; -struct peer; -struct node; - -/* Helper to get non-signature, non-timestamp parts of (valid!) channel_update */ -void get_cupdate_parts(const u8 *channel_update, - const u8 *parts[2], - size_t sizes[2]); - - -/* Is this channel_update different from prev (not sigs and timestamps)? - * is_halfchan_defined(hc) must be true! */ -bool cupdate_different(struct gossip_store *gs, - const struct half_chan *hc, - const u8 *cupdate); - -/* Is this node_announcement different from prev (not sigs and timestamps)? - * node->bcast.index must be non-zero! */ -bool nannounce_different(struct gossip_store *gs, - const struct node *node, - 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, bool startup); - -/* Disable this local channel (lazily) */ -void local_disable_chan(struct daemon *daemon, const struct chan *chan, int direction); - -/* Re-enable this local channel */ -void local_enable_chan(struct daemon *daemon, const struct chan *chan, int direction); - -/* This is a refresh of a local channel which is > 13 days old. */ -void refresh_local_channel(struct daemon *daemon, - struct chan *chan, int direction); - -/* channeld (via lightningd) asks us to update the local channel. */ -void handle_local_channel_update(struct daemon *daemon, const u8 *msg); - -/* lightningd tells us it used the last channel_update we sent. */ -void handle_used_local_channel_update(struct daemon *daemon, const u8 *msg); - -#endif /* LIGHTNING_GOSSIPD_GOSSIP_GENERATION_H */ diff --git a/gossipd/gossip_store.c b/gossipd/gossip_store.c index 5130cc6bf617..2c03719d54d7 100644 --- a/gossipd/gossip_store.c +++ b/gossipd/gossip_store.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -17,8 +16,8 @@ #include #define GOSSIP_STORE_TEMP_FILENAME "gossip_store.tmp" -/* We write it as major version 0, minor version 12 */ -#define GOSSIP_STORE_VER ((0 << 5) | 12) +/* We write it as major version 0, minor version 13 */ +#define GOSSIP_STORE_VER ((0 << 5) | 13) struct gossip_store { /* This is false when we're loading */ @@ -107,25 +106,85 @@ static bool append_msg(int fd, const u8 *msg, u32 timestamp, * v10 removed any remaining non-htlc-max channel_update. * v11 mandated channel_updates use the htlc_maximum_msat field * v12 added the zombie flag for expired channel updates + * v13 removed private gossip entries */ static bool can_upgrade(u8 oldversion) { - return oldversion >= 9 && oldversion <= 11; + return oldversion >= 9 && oldversion <= 12; +} + +/* On upgrade, do best effort on private channels: hand them to + * lightningd as if we just receive them, before removing from the + * store */ +static void give_lightningd_canned_private_update(struct routing_state *rstate, + const u8 *msg) +{ + u8 *update; + secp256k1_ecdsa_signature signature; + struct bitcoin_blkid chain_hash; + struct short_channel_id short_channel_id; + u32 timestamp; + u8 message_flags, channel_flags; + u16 cltv_expiry_delta; + struct amount_msat htlc_minimum_msat, htlc_maximum_msat; + u32 fee_base_msat, fee_proportional_millionths; + + if (!fromwire_gossip_store_private_update_obs(tmpctx, msg, &update)) { + status_broken("Could not parse private update %s", + tal_hex(tmpctx, msg)); + return; + } + if (!fromwire_channel_update(update, + &signature, + &chain_hash, + &short_channel_id, + ×tamp, + &message_flags, + &channel_flags, + &cltv_expiry_delta, + &htlc_minimum_msat, + &fee_base_msat, + &fee_proportional_millionths, + &htlc_maximum_msat)) { + status_broken("Could not parse inner private update %s", + tal_hex(tmpctx, msg)); + return; + } + + /* From NULL source (i.e. trust us!) */ + tell_lightningd_peer_update(rstate, + NULL, + short_channel_id, + fee_base_msat, + fee_proportional_millionths, + cltv_expiry_delta, + htlc_minimum_msat, + htlc_maximum_msat); } static bool upgrade_field(u8 oldversion, struct routing_state *rstate, u8 **msg) { + int type = fromwire_peektype(*msg); assert(can_upgrade(oldversion)); - if (oldversion == 10) { + if (oldversion <= 10) { /* Remove old channel_update with no htlc_maximum_msat */ - if (fromwire_peektype(*msg) == WIRE_CHANNEL_UPDATE + if (type == WIRE_CHANNEL_UPDATE && tal_bytelen(*msg) == 130) { *msg = tal_free(*msg); } } + if (oldversion <= 12) { + /* Remove private entries */ + if (type == WIRE_GOSSIP_STORE_PRIVATE_CHANNEL_OBS) { + *msg = tal_free(*msg); + } else if (type == WIRE_GOSSIP_STORE_PRIVATE_UPDATE_OBS) { + give_lightningd_canned_private_update(rstate, *msg); + *msg = tal_free(*msg); + } + } return true; } @@ -468,9 +527,7 @@ bool gossip_store_compact(struct gossip_store *gs) goto unlink_disable; /* We track location of all these message types. */ - if (msgtype == WIRE_GOSSIP_STORE_PRIVATE_CHANNEL - || msgtype == WIRE_GOSSIP_STORE_PRIVATE_UPDATE - || msgtype == WIRE_CHANNEL_ANNOUNCEMENT + if (msgtype == WIRE_CHANNEL_ANNOUNCEMENT || msgtype == WIRE_CHANNEL_UPDATE || msgtype == WIRE_NODE_ANNOUNCEMENT) { omap = tal(offmap, struct offset_map); @@ -575,14 +632,6 @@ u64 gossip_store_add(struct gossip_store *gs, const u8 *gossip_msg, return off; } -u64 gossip_store_add_private_update(struct gossip_store *gs, const u8 *update) -{ - /* A local update for an unannounced channel: not broadcastable, but - * otherwise the same as a normal channel_update */ - const u8 *pupdate = towire_gossip_store_private_update(tmpctx, update); - return gossip_store_add(gs, pupdate, 0, false, false, false, NULL); -} - void gossip_store_mark_dying(struct gossip_store *gs, const struct broadcastable *bcast, int type) @@ -778,20 +827,6 @@ const u8 *gossip_store_get(const tal_t *ctx, return msg; } -const u8 *gossip_store_get_private_update(const tal_t *ctx, - struct gossip_store *gs, - u64 offset) -{ - const u8 *pmsg = gossip_store_get(tmpctx, gs, offset); - u8 *msg; - - if (!fromwire_gossip_store_private_update(ctx, pmsg, &msg)) - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Failed to decode private update @%"PRIu64": %s", - offset, tal_hex(tmpctx, pmsg)); - return msg; -} - int gossip_store_readonly_fd(struct gossip_store *gs) { int fd = open(GOSSIP_STORE_FILENAME, O_RDONLY); @@ -845,25 +880,6 @@ u32 gossip_store_load(struct routing_state *rstate, struct gossip_store *gs) spam = (be16_to_cpu(hdr.flags) & GOSSIP_STORE_RATELIMIT_BIT); switch (fromwire_peektype(msg)) { - case WIRE_GOSSIP_STORE_PRIVATE_CHANNEL: { - u8 *priv_chan_ann; - struct amount_sat sat; - if (!fromwire_gossip_store_private_channel(msg, msg, - &sat, - &priv_chan_ann)) { - bad = "Bad private_channel"; - goto badmsg; - } - - if (!routing_add_private_channel(rstate, NULL, - sat, priv_chan_ann, - gs->len)) { - bad = "Bad add_private_channel"; - goto badmsg; - } - stats[0]++; - break; - } case WIRE_GOSSIP_STORE_CHANNEL_AMOUNT: if (!fromwire_gossip_store_channel_amount(msg, &satoshis)) { @@ -904,12 +920,6 @@ u32 gossip_store_load(struct routing_state *rstate, struct gossip_store *gs) remember_chan_dying(rstate, &scid, deadline, gs->len); break; } - case WIRE_GOSSIP_STORE_PRIVATE_UPDATE: - if (!fromwire_gossip_store_private_update(tmpctx, msg, &msg)) { - bad = "invalid gossip_store_private_update"; - goto badmsg; - } - /* fall thru */ case WIRE_CHANNEL_UPDATE: if (!routing_add_channel_update(rstate, take(msg), gs->len, diff --git a/gossipd/gossip_store.h b/gossipd/gossip_store.h index a8d7d7bc6888..b318842f150a 100644 --- a/gossipd/gossip_store.h +++ b/gossipd/gossip_store.h @@ -28,11 +28,6 @@ struct gossip_store *gossip_store_new(struct routing_state *rstate); */ u32 gossip_store_load(struct routing_state *rstate, struct gossip_store *gs); -/** - * Add a private channel_update message to the gossip_store - */ -u64 gossip_store_add_private_update(struct gossip_store *gs, const u8 *update); - /** * Add a gossip message to the gossip_store (and optional addendum) * @gs: gossip store @@ -96,15 +91,6 @@ const u8 *gossip_store_get(const tal_t *ctx, struct gossip_store *gs, u64 offset); -/** - * Direct store accessor: loads private gossip msg back from store. - * - * Caller must ensure offset != 0. Never returns NULL. - */ -const u8 *gossip_store_get_private_update(const tal_t *ctx, - struct gossip_store *gs, - u64 offset); - /* Exposed for dev-compact-gossip-store to force compaction. */ bool gossip_store_compact(struct gossip_store *gs); diff --git a/gossipd/gossip_store_wire.csv b/gossipd/gossip_store_wire.csv index 55e62c3bd61f..b0f81c371293 100644 --- a/gossipd/gossip_store_wire.csv +++ b/gossipd/gossip_store_wire.csv @@ -9,14 +9,14 @@ msgtype,gossip_store_channel_amount,4101 msgdata,gossip_store_channel_amount,satoshis,amount_sat, # Mimics a channel_announce, except signatures are all-zero -msgtype,gossip_store_private_channel,4104 -msgdata,gossip_store_private_channel,satoshis,amount_sat, -msgdata,gossip_store_private_channel,len,u16, -msgdata,gossip_store_private_channel,announcement,u8,len +msgtype,gossip_store_private_channel_obs,4104 +msgdata,gossip_store_private_channel_obs,satoshis,amount_sat, +msgdata,gossip_store_private_channel_obs,len,u16, +msgdata,gossip_store_private_channel_obs,announcement,u8,len -msgtype,gossip_store_private_update,4102 -msgdata,gossip_store_private_update,len,u16, -msgdata,gossip_store_private_update,update,u8,len +msgtype,gossip_store_private_update_obs,4102 +msgdata,gossip_store_private_update_obs,len,u16, +msgdata,gossip_store_private_update_obs,update,u8,len msgtype,gossip_store_delete_chan,4103 msgdata,gossip_store_delete_chan,scid,short_channel_id, diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index 35015ec49012..af6ec048c1ec 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -27,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -47,41 +45,6 @@ bool peer_node_id_eq(const struct peer *peer, const struct node_id *node_id) return node_id_eq(&peer->id, node_id); } -/*~ A channel consists of a `struct half_chan` for each direction, each of - * which has a `flags` word from the `channel_update`; bit 1 is - * ROUTING_FLAGS_DISABLED in the `channel_update`. But we also keep a local - * whole-channel flag which indicates it's not available; we use this when a - * peer disconnects, and generate a `channel_update` to tell the world lazily - * when someone asks. */ -static void peer_disable_channels(struct daemon *daemon, const struct node *node) -{ - /* If this peer had a channel with us, mark it disabled. */ - struct chan_map_iter i; - const struct chan *c; - - for (c = first_chan(node, &i); c; c = next_chan(node, &i)) { - int direction; - if (!local_direction(daemon->rstate, c, &direction)) - continue; - local_disable_chan(daemon, c, direction); - } -} - -/*~ This cancels the soft-disables when the peer reconnects. */ -static void peer_enable_channels(struct daemon *daemon, const struct node *node) -{ - /* If this peer had a channel with us, mark it disabled. */ - struct chan_map_iter i; - const struct chan *c; - - for (c = first_chan(node, &i); c; c = next_chan(node, &i)) { - int direction; - if (!local_direction(daemon->rstate, c, &direction)) - continue; - local_enable_chan(daemon, c, direction); - } -} - /*~ Destroy a peer, usually because the per-peer daemon has exited. * * Were you wondering why we call this "destroy_peer" and not "peer_destroy"? @@ -91,16 +54,10 @@ static void peer_enable_channels(struct daemon *daemon, const struct node *node) */ static void destroy_peer(struct peer *peer) { - struct node *node; - /* Remove it from the peers table */ - peer_node_id_map_del(peer->daemon->peers, peer);; - - /* If we have a channel with this peer, disable it. */ - node = get_node(peer->daemon->rstate, &peer->id); - if (node) - peer_disable_channels(peer->daemon, node); + peer_node_id_map_del(peer->daemon->peers, peer); + /* Sorry seeker, this one is gone. */ seeker_peer_gone(peer->daemon->seeker, peer); } @@ -146,15 +103,6 @@ void queue_peer_from_store(struct peer *peer, queue_peer_msg(peer, take(gossip_store_get(NULL, gs, bcast->index))); } -static void queue_priv_update(struct peer *peer, - const struct broadcastable *bcast) -{ - struct gossip_store *gs = peer->daemon->rstate->gs; - queue_peer_msg(peer, - take(gossip_store_get_private_update(NULL, gs, - bcast->index))); -} - /*~ We don't actually keep node_announcements in memory; we keep them in * a file called `gossip_store`. If we need some node details, we reload * and reparse. It's slow, but generally rare. */ @@ -290,12 +238,6 @@ static u8 *handle_channel_update_msg(struct peer *peer, const u8 *msg) if (unknown_scid.u64 != 0) query_unknown_channel(peer->daemon, peer, &unknown_scid); - /*~ As a nasty compromise in the spec, we only forward `channel_announce` - * once we have a `channel_update`; the channel isn't *usable* for - * 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, false); return NULL; } @@ -311,114 +253,6 @@ static u8 *handle_node_announce(struct peer *peer, const u8 *msg) return err; } -static void handle_local_channel_announcement(struct daemon *daemon, const u8 *msg) -{ - u8 *cannouncement; - const u8 *err; - struct node_id id; - - if (!fromwire_gossipd_local_channel_announcement(msg, msg, - &id, - &cannouncement)) - master_badmsg(WIRE_GOSSIPD_LOCAL_CHANNEL_ANNOUNCEMENT, msg); - - err = handle_channel_announcement_msg(daemon, &id, cannouncement); - if (err) { - status_peer_broken(&id, "invalid local_channel_announcement %s (%s)", - tal_hex(tmpctx, msg), - tal_hex(tmpctx, err)); - } -} - - -/* channeld (via lightningd) tells us about (as-yet?) unannounce channel. - * It needs us to put it in gossip_store. */ -static void handle_local_private_channel(struct daemon *daemon, const u8 *msg) -{ - struct node_id id; - struct amount_sat capacity; - u8 *features; - struct short_channel_id scid; - const u8 *cannounce; - struct chan *zombie; - - if (!fromwire_gossipd_local_private_channel(msg, msg, - &id, &capacity, &scid, - &features)) - master_badmsg(WIRE_GOSSIPD_LOCAL_PRIVATE_CHANNEL, msg); - - status_debug("received private channel announcement from channeld for %s", - type_to_string(tmpctx, struct short_channel_id, &scid)); - cannounce = private_channel_announcement(tmpctx, - &scid, - &daemon->id, - &id, - features); - /* If there is already a zombie announcement for this channel in the - * store we can disregard this one. */ - zombie = get_channel(daemon->rstate, &scid); - if (zombie && (zombie->half[0].zombie || zombie->half[1].zombie)){ - status_debug("received channel announcement for %s," - " but it is a zombie; discarding", - type_to_string(tmpctx, struct short_channel_id, - &scid)); - return; - } - - if (!routing_add_private_channel(daemon->rstate, &id, capacity, - cannounce, 0)) { - status_peer_broken(&id, "bad add_private_channel %s", - tal_hex(tmpctx, cannounce)); - } -} - -/* lightningd tells us it has discovered and verified new `remote_addr`. - * We can use this to update our node announcement. */ -static void handle_discovered_ip(struct daemon *daemon, const u8 *msg) -{ - struct wireaddr discovered_ip; - size_t count_announceable; - - if (!fromwire_gossipd_discovered_ip(msg, &discovered_ip)) - master_badmsg(WIRE_GOSSIPD_DISCOVERED_IP, msg); - - switch (discovered_ip.type) { - case ADDR_TYPE_IPV4: - if (daemon->discovered_ip_v4 != NULL && - wireaddr_eq_without_port(daemon->discovered_ip_v4, - &discovered_ip)) - break; - tal_free(daemon->discovered_ip_v4); - daemon->discovered_ip_v4 = tal_dup(daemon, struct wireaddr, - &discovered_ip); - goto update_node_annoucement; - case ADDR_TYPE_IPV6: - if (daemon->discovered_ip_v6 != NULL && - wireaddr_eq_without_port(daemon->discovered_ip_v6, - &discovered_ip)) - break; - tal_free(daemon->discovered_ip_v6); - daemon->discovered_ip_v6 = tal_dup(daemon, struct wireaddr, - &discovered_ip); - goto update_node_annoucement; - - /* ignore all other cases */ - case ADDR_TYPE_TOR_V2_REMOVED: - case ADDR_TYPE_TOR_V3: - case ADDR_TYPE_DNS: - break; - } - return; - -update_node_annoucement: - count_announceable = tal_count(daemon->announceable); - if ((daemon->ip_discovery == OPT_AUTOBOOL_AUTO && count_announceable == 0) || - daemon->ip_discovery == OPT_AUTOBOOL_TRUE) - status_debug("Update our node_announcement for discovered address: %s", - fmt_wireaddr(tmpctx, &discovered_ip)); - maybe_send_own_node_announce(daemon, false); -} - /* Statistically, how many peers to we tell about each channel? */ #define GOSSIP_SPAM_REDUNDANCY 5 @@ -443,19 +277,6 @@ static void dump_our_gossip(struct daemon *daemon, struct peer *peer) return; for (chan = first_chan(me, &it); chan; chan = next_chan(me, &it)) { - /* Don't leak private channels, unless it's with you! */ - if (!is_chan_public(chan)) { - int dir = half_chan_idx(me, chan); - - if (node_id_eq(&chan->nodes[!dir]->id, &peer->id) - && is_halfchan_defined(&chan->half[dir])) { - /* There's no announce for this, of course! */ - /* Private channel updates are wrapped in the store. */ - queue_priv_update(peer, &chan->half[dir].bcast); - } - continue; - } - tal_arr_expand(&chans, chan); } @@ -497,7 +318,6 @@ static void dump_our_gossip(struct daemon *daemon, struct peer *peer) static void connectd_new_peer(struct daemon *daemon, const u8 *msg) { struct peer *peer = tal(daemon, struct peer); - struct node *node; if (!fromwire_gossipd_new_peer(msg, &peer->id, &peer->gossip_queries_feature)) { @@ -527,10 +347,6 @@ static void connectd_new_peer(struct daemon *daemon, const u8 *msg) peer_node_id_map_add(daemon->peers, peer); tal_add_destructor(peer, destroy_peer); - node = get_node(daemon->rstate, &peer->id); - if (node) - peer_enable_channels(daemon, node); - /* Send everything we know about our own channels */ dump_our_gossip(daemon, peer); @@ -723,58 +539,13 @@ static struct io_plan *connectd_req(struct io_conn *conn, */ static void gossip_refresh_network(struct daemon *daemon) { - u64 now = gossip_time_now(daemon->rstate).ts.tv_sec; - s64 highwater; - struct node *n; - - /* Send out 1 day before deadline */ - highwater = now - (GOSSIP_PRUNE_INTERVAL(daemon->rstate->dev_fast_gossip) - - GOSSIP_BEFORE_DEADLINE(daemon->rstate->dev_fast_gossip_prune)); - /* Schedule next run now */ notleak(new_reltimer(&daemon->timers, daemon, time_from_sec(GOSSIP_PRUNE_INTERVAL(daemon->rstate->dev_fast_gossip_prune)/4), gossip_refresh_network, daemon)); - /* Find myself in the network */ - n = get_node(daemon->rstate, &daemon->id); - if (n) { - /* Iterate through all outgoing connection and check whether - * it's time to re-announce */ - struct chan_map_iter i; - struct chan *c; - - for (c = first_chan(n, &i); c; c = next_chan(n, &i)) { - struct half_chan *hc; - int direction; - - if (!local_direction(daemon->rstate, c, &direction)) - continue; - - hc = &c->half[direction]; - - if (!is_halfchan_defined(hc)) { - /* Connection is not announced yet, so don't even - * try to re-announce it */ - continue; - } - - if (hc->bcast.timestamp > highwater) { - /* No need to send a keepalive update message */ - continue; - } - - status_debug("Sending keepalive channel_update" - " for %s/%u", - type_to_string(tmpctx, - struct short_channel_id, - &c->scid), direction); - refresh_local_channel(daemon, c, direction); - } - } - - /* Now we've refreshed our channels, we can prune without clobbering - * them */ + /* Prune: I hope lightningd is keeping up with our own channel + * refreshes! */ route_prune(daemon->rstate); } @@ -793,10 +564,6 @@ static void tell_master_local_cupdates(struct daemon *daemon) int direction; const u8 *cupdate; - /* We don't provide update_channel for unannounced channels */ - if (!is_chan_public(c)) - continue; - if (!local_direction(daemon->rstate, c, &direction)) continue; @@ -812,6 +579,17 @@ static void tell_master_local_cupdates(struct daemon *daemon) &c->scid, cupdate))); } + + /* Tell lightningd about our current node_announcement, if any */ + if (me->bcast.index) { + const u8 *nannounce; + nannounce = gossip_store_get(tmpctx, + daemon->rstate->gs, + me->bcast.index); + daemon_conn_send(daemon->master, + take(towire_gossipd_init_nannounce(NULL, + nannounce))); + } } struct peer *first_random_peer(struct daemon *daemon, @@ -856,13 +634,9 @@ static void gossip_init(struct daemon *daemon, const u8 *msg) &chainparams, &daemon->our_features, &daemon->id, - daemon->rgb, - daemon->alias, - &daemon->announceable, &dev_gossip_time, &dev_fast_gossip, - &dev_fast_gossip_prune, - &daemon->ip_discovery)) { + &dev_fast_gossip_prune)) { master_badmsg(WIRE_GOSSIPD_INIT, msg); } @@ -881,10 +655,6 @@ static void gossip_init(struct daemon *daemon, const u8 *msg) if (daemon->rstate->last_timestamp > timestamp) daemon->rstate->last_timestamp = timestamp; - /* If that announced channels, we can announce ourselves (options - * or addresses might have changed!) */ - maybe_send_own_node_announce(daemon, true); - /* Start the twice- weekly refresh timer. */ notleak(new_reltimer(&daemon->timers, daemon, time_from_sec(GOSSIP_PRUNE_INTERVAL(daemon->rstate->dev_fast_gossip_prune) / 4), @@ -900,7 +670,7 @@ static void gossip_init(struct daemon *daemon, const u8 *msg) tal_add_destructor(daemon->connectd, master_or_connectd_gone); /* Tell it about all our local (public) channel_update messages, - * so it doesn't unnecessarily regenerate them. */ + * and node_announcement, so it doesn't unnecessarily regenerate them. */ tell_master_local_cupdates(daemon); /* OK, we are ready. */ @@ -946,6 +716,7 @@ static void dev_gossip_memleak(struct daemon *daemon, const u8 *msg) /* Now delete daemon and those which it has pointers to. */ memleak_scan_obj(memtable, daemon); memleak_scan_htable(memtable, &daemon->peers->raw); + dev_seeker_memleak(memtable, daemon->seeker); found_leak = dump_memleak(memtable, memleak_status_broken, NULL); daemon_conn_send(daemon->master, @@ -992,10 +763,6 @@ static void handle_txout_reply(struct daemon *daemon, const u8 *msg) /* If we looking specifically for this, we no longer are. */ remove_unknown_scid(daemon->seeker, &scid, good); - - /* 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, false); } /*~ lightningd tells us when about a gossip message directly, when told to by @@ -1042,23 +809,6 @@ static void inject_gossip(struct daemon *daemon, const u8 *msg) take(towire_gossipd_addgossip_reply(NULL, err))); } -static void handle_new_lease_rates(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); - - 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); -} - /*~ This is where lightningd tells us that a channel's funding transaction has * been spent. */ static void handle_outpoints_spent(struct daemon *daemon, const u8 *msg) @@ -1081,38 +831,6 @@ static void handle_outpoints_spent(struct daemon *daemon, const u8 *msg) } } -/*~ This is sent by lightningd when it kicks off 'closingd': we disable it - * in both directions. - * - * We'll leave it to handle_outpoint_spent to delete the channel from our view - * once the close gets confirmed. This avoids having strange states in which the - * channel is list in our peer list but won't be returned when listing public - * channels. This does not send out updates since that's triggered by the peer - * connection closing. - */ -static void handle_local_channel_close(struct daemon *daemon, const u8 *msg) -{ - struct short_channel_id scid; - struct chan *chan; - struct routing_state *rstate = daemon->rstate; - if (!fromwire_gossipd_local_channel_close(msg, &scid)) - master_badmsg(WIRE_GOSSIPD_LOCAL_CHANNEL_CLOSE, msg); - - chan = get_channel(rstate, &scid); - if (chan) { - int direction; - - if (!local_direction(rstate, chan, &direction)) { - status_broken("Non-local channel close %s", - type_to_string(tmpctx, - struct short_channel_id, - &scid)); - } else { - local_disable_chan(daemon, chan, direction); - } - } -} - /*~ This routine handles all the commands from lightningd. */ static struct io_plan *recv_req(struct io_conn *conn, const u8 *msg, @@ -1133,10 +851,6 @@ static struct io_plan *recv_req(struct io_conn *conn, handle_outpoints_spent(daemon, msg); goto done; - case WIRE_GOSSIPD_LOCAL_CHANNEL_CLOSE: - handle_local_channel_close(daemon, msg); - goto done; - case WIRE_GOSSIPD_NEW_BLOCKHEIGHT: new_blockheight(daemon, msg); goto done; @@ -1145,32 +859,9 @@ static struct io_plan *recv_req(struct io_conn *conn, inject_gossip(daemon, msg); goto done; - case WIRE_GOSSIPD_NEW_LEASE_RATES: - handle_new_lease_rates(daemon, msg); - goto done; - case WIRE_GOSSIPD_GET_ADDRS: return handle_get_address(conn, daemon, msg); - case WIRE_GOSSIPD_USED_LOCAL_CHANNEL_UPDATE: - handle_used_local_channel_update(daemon, msg); - goto done; - - case WIRE_GOSSIPD_LOCAL_CHANNEL_UPDATE: - handle_local_channel_update(daemon, msg); - goto done; - - case WIRE_GOSSIPD_LOCAL_CHANNEL_ANNOUNCEMENT: - handle_local_channel_announcement(daemon, msg); - goto done; - - case WIRE_GOSSIPD_LOCAL_PRIVATE_CHANNEL: - handle_local_private_channel(daemon, msg); - goto done; - - case WIRE_GOSSIPD_DISCOVERED_IP: - handle_discovered_ip(daemon, msg); - goto done; case WIRE_GOSSIPD_DEV_SET_MAX_SCIDS_ENCODE_SIZE: if (daemon->developer) { dev_set_max_scids_encode_size(daemon, msg); @@ -1198,6 +889,7 @@ static struct io_plan *recv_req(struct io_conn *conn, /* We send these, we don't receive them */ case WIRE_GOSSIPD_INIT_CUPDATE: + case WIRE_GOSSIPD_INIT_NANNOUNCE: case WIRE_GOSSIPD_INIT_REPLY: case WIRE_GOSSIPD_GET_TXOUT: case WIRE_GOSSIPD_DEV_MEMLEAK_REPLY: @@ -1205,7 +897,6 @@ static struct io_plan *recv_req(struct io_conn *conn, case WIRE_GOSSIPD_ADDGOSSIP_REPLY: case WIRE_GOSSIPD_NEW_BLOCKHEIGHT_REPLY: case WIRE_GOSSIPD_GET_ADDRS_REPLY: - case WIRE_GOSSIPD_GOT_LOCAL_CHANNEL_UPDATE: case WIRE_GOSSIPD_REMOTE_CHANNEL_UPDATE: break; } @@ -1232,14 +923,7 @@ int main(int argc, char *argv[]) daemon->peers = tal(daemon, struct peer_node_id_map); peer_node_id_map_init(daemon->peers); daemon->deferred_txouts = tal_arr(daemon, struct short_channel_id, 0); - daemon->node_announce_timer = NULL; - daemon->node_announce_regen_timer = NULL; daemon->current_blockheight = 0; /* i.e. unknown */ - daemon->rates = NULL; - daemon->discovered_ip_v4 = NULL; - daemon->discovered_ip_v6 = NULL; - daemon->ip_discovery = OPT_AUTOBOOL_AUTO; - list_head_init(&daemon->deferred_updates); /* 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 a9271f72d81e..6d4b6ddbf902 100644 --- a/gossipd/gossipd.h +++ b/gossipd/gossipd.h @@ -56,24 +56,6 @@ struct daemon { /* Timers: we batch gossip, and also refresh announcements */ struct timers timers; - /* Alias (not NUL terminated) and favorite color for node_announcement */ - u8 alias[32]; - u8 rgb[3]; - - /* What addresses we can actually announce. */ - struct wireaddr *announceable; - - /* verified remote_addr as reported by recent peers */ - struct wireaddr *discovered_ip_v4; - struct wireaddr *discovered_ip_v6; - enum opt_autobool ip_discovery; - - /* Timer until we can send an updated node_announcement */ - struct oneshot *node_announce_timer; - - /* Timer until we should force a new new node_announcement */ - struct oneshot *node_announce_regen_timer; - /* Channels we have an announce for, but aren't deep enough. */ struct short_channel_id *deferred_txouts; @@ -82,12 +64,6 @@ 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; - - /* Any of our channel_updates we're deferring. */ - struct list_head deferred_updates; }; struct range_query_reply { diff --git a/gossipd/gossipd_wire.csv b/gossipd/gossipd_wire.csv index 0dd73b6696fc..63dabd05ea5b 100644 --- a/gossipd/gossipd_wire.csv +++ b/gossipd/gossipd_wire.csv @@ -9,14 +9,9 @@ msgtype,gossipd_init,3000 msgdata,gossipd_init,chainparams,chainparams, msgdata,gossipd_init,our_features,feature_set, msgdata,gossipd_init,id,node_id, -msgdata,gossipd_init,rgb,u8,3 -msgdata,gossipd_init,alias,u8,32 -msgdata,gossipd_init,num_announceable,u16, -msgdata,gossipd_init,announceable,wireaddr,num_announceable msgdata,gossipd_init,dev_gossip_time,?u32, msgdata,gossipd_init,dev_fast_gossip,bool, msgdata,gossipd_init,dev_fast_gossip_prune,bool, -msgdata,gossipd_init,ip_discovery,u32, # Gossipd tells us all our public channel_updates before init_reply. msgtype,gossipd_init_cupdate,3101 @@ -24,6 +19,11 @@ msgdata,gossipd_init_cupdate,scid,short_channel_id, msgdata,gossipd_init_cupdate,len,u16, msgdata,gossipd_init_cupdate,cupdate,u8,len +# Gossipd tells us our node_announcement before init_reply. +msgtype,gossipd_init_nannounce,3102 +msgdata,gossipd_init_nannounce,len,u16, +msgdata,gossipd_init_nannounce,nannounce,u8,len + msgtype,gossipd_init_reply,3100 # In developer mode, we can mess with time. @@ -34,10 +34,6 @@ msgdata,gossipd_dev_set_time,dev_gossip_time,u32, msgtype,gossipd_dev_set_max_scids_encode_size,3030 msgdata,gossipd_dev_set_max_scids_encode_size,max,u32, -# gossipd->master: we're closing this channel. -msgtype,gossipd_local_channel_close,3027 -msgdata,gossipd_local_channel_close,short_channel_id,short_channel_id, - # Gossipd->master get this tx output please. msgtype,gossipd_get_txout,3018 msgdata,gossipd_get_txout,short_channel_id,short_channel_id, @@ -84,10 +80,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, - # Lightningd asks gossipd for any known addresses for that node. msgtype,gossipd_get_addrs,3050 msgdata,gossipd_get_addrs,id,node_id, @@ -96,47 +88,6 @@ msgtype,gossipd_get_addrs_reply,3150 msgdata,gossipd_get_addrs_reply,num,u16, msgdata,gossipd_get_addrs_reply,addrs,wireaddr,num -# Tell master a local channel update (so it can serve errors). -msgtype,gossipd_got_local_channel_update,3151 -msgdata,gossipd_got_local_channel_update,scid,short_channel_id, -msgdata,gossipd_got_local_channel_update,len,u16, -msgdata,gossipd_got_local_channel_update,channel_update,u8,len - -# Send this channel_update. -msgtype,gossipd_local_channel_update,3004 -msgdata,gossipd_local_channel_update,id,node_id, -msgdata,gossipd_local_channel_update,short_channel_id,short_channel_id, -msgdata,gossipd_local_channel_update,enable,bool, -msgdata,gossipd_local_channel_update,cltv_expiry_delta,u16, -msgdata,gossipd_local_channel_update,htlc_minimum_msat,amount_msat, -msgdata,gossipd_local_channel_update,fee_base_msat,u32, -msgdata,gossipd_local_channel_update,fee_proportional_millionths,u32, -msgdata,gossipd_local_channel_update,htlc_maximum_msat,amount_msat, -msgdata,gossipd_local_channel_update,public,bool, - -# Send this channel_announcement -msgtype,gossipd_local_channel_announcement,3006 -msgdata,gossipd_local_channel_announcement,id,node_id, -msgdata,gossipd_local_channel_announcement,len,u16, -msgdata,gossipd_local_channel_announcement,cannounce,u8,len - -# Tell gossipd about a private channel (to put it in the store) -# cannounce has same structure, dummy sigs. -msgtype,gossipd_local_private_channel,3008 -msgdata,gossipd_local_private_channel,id,node_id, -msgdata,gossipd_local_private_channel,capacity,amount_sat, -msgdata,gossipd_local_private_channel,scid,short_channel_id, -msgdata,gossipd_local_private_channel,len,u16, -msgdata,gossipd_local_private_channel,features,u8,len - -# Tell gossipd we used the channel update (in case it was deferred) -msgtype,gossipd_used_local_channel_update,3052 -msgdata,gossipd_used_local_channel_update,scid,short_channel_id, - -# Tell gossipd we have verified a new public IP by the remote_addr feature -msgtype,gossipd_discovered_ip,3009 -msgdata,gossipd_discovered_ip,discovered_ip,wireaddr, - subtype,peer_update subtypedata,peer_update,scid,short_channel_id, subtypedata,peer_update,fee_base,u32, diff --git a/gossipd/queries.c b/gossipd/queries.c index d8b658862272..61d70293a893 100644 --- a/gossipd/queries.c +++ b/gossipd/queries.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -324,6 +323,30 @@ static void send_reply_channel_range(struct peer *peer, queue_peer_msg(peer, take(msg)); } +/* Helper to get non-signature, non-timestamp parts of (valid!) channel_update */ +void get_cupdate_parts(const u8 *channel_update, + const u8 *parts[2], + size_t sizes[2]) +{ + /* BOLT #7: + * + * 1. type: 258 (`channel_update`) + * 2. data: + * * [`signature`:`signature`] + * * [`chain_hash`:`chain_hash`] + * * [`short_channel_id`:`short_channel_id`] + * * [`u32`:`timestamp`] + *... + */ + /* Note: 2 bytes for `type` field */ + /* We already checked it's valid before accepting */ + assert(tal_count(channel_update) > 2 + 64 + 32 + 8 + 4); + parts[0] = channel_update + 2 + 64; + sizes[0] = 32 + 8; + parts[1] = channel_update + 2 + 64 + 32 + 8 + 4; + sizes[1] = tal_count(channel_update) - (64 + 2 + 32 + 8 + 4); +} + /* BOLT #7: * * The checksum of a `channel_update` is the CRC32C checksum as specified in @@ -351,7 +374,7 @@ static void get_checksum_and_timestamp(struct routing_state *rstate, { const struct half_chan *hc = &chan->half[direction]; - if (!is_chan_public(chan) || !is_halfchan_defined(hc)) { + if (!is_halfchan_defined(hc)) { *tstamp = *csum = 0; } else { const u8 *update = gossip_store_get(tmpctx, rstate->gs, @@ -468,9 +491,6 @@ static struct short_channel_id *gather_range(const tal_t *ctx, /* FIXME: Store csum in header. */ chan = get_channel(rstate, &scid); - if (!is_chan_public(chan)) - continue; - tal_arr_expand(&scids, scid); /* Don't calc csums if we don't even care */ @@ -923,7 +943,7 @@ static bool maybe_send_query_responses_peer(struct peer *peer) struct chan *chan; chan = get_channel(rstate, &peer->scid_queries[i]); - if (!chan || !is_chan_public(chan)) + if (!chan) continue; /* BOLT #7: diff --git a/gossipd/queries.h b/gossipd/queries.h index f2dd5847d03a..727f6ef1023f 100644 --- a/gossipd/queries.h +++ b/gossipd/queries.h @@ -7,6 +7,7 @@ struct channel_update_timestamps; struct daemon; struct io_conn; struct peer; +struct range_query_reply; struct short_channel_id; /* Various handlers when peer fwds a gossip query msg: return is NULL or @@ -60,4 +61,8 @@ struct io_plan *dev_query_channel_range(struct io_conn *conn, * of short_channel_ids we'll encode, using dev_set_max_scids_encode_size. */ void dev_set_max_scids_encode_size(struct daemon *daemon, const u8 *msg); +void get_cupdate_parts(const u8 *channel_update, + const u8 *parts[2], + size_t sizes[2]); + #endif /* LIGHTNING_GOSSIPD_QUERIES_H */ diff --git a/gossipd/routing.c b/gossipd/routing.c index a236a102a532..65f620b0fd59 100644 --- a/gossipd/routing.c +++ b/gossipd/routing.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -11,9 +12,9 @@ #include #include #include -#include #include #include +#include #include #ifndef SUPERVERBOSE @@ -294,7 +295,6 @@ struct routing_state *new_routing_state(const tal_t *ctx, rstate->daemon = daemon; rstate->nodes = new_node_map(rstate); rstate->gs = gossip_store_new(rstate); - rstate->local_channel_announced = false; rstate->last_timestamp = 0; rstate->dying_channels = tal_arr(rstate, struct dying_channel, 0); @@ -389,20 +389,6 @@ static bool is_chan_zombie(struct chan *chan) return false; } -/* We've received a channel_announce for a channel attached to this node: - * otherwise it's in the map only because it's a peer, or us. */ -static bool node_has_public_channels(struct node *node) -{ - struct chan_map_iter i; - struct chan *c; - - for (c = first_chan(node, &i); c; c = next_chan(node, &i)) { - if (is_chan_public(c) && !is_chan_zombie(c)) - return true; - } - return false; -} - static bool is_node_zombie(struct node* node) { struct chan_map_iter i; @@ -423,8 +409,6 @@ bool node_has_broadcastable_channels(const struct node *node) struct chan *c; for (c = first_chan(node, &i); c; c = next_chan(node, &i)) { - if (!is_chan_public(c)) - continue; if (is_chan_zombie(c)) continue; if (is_halfchan_defined(&c->half[0]) @@ -440,9 +424,6 @@ static bool node_announce_predates_channels(const struct node *node) struct chan *c; for (c = first_chan(node, &i); c; c = next_chan(node, &i)) { - if (!is_chan_public(c)) - continue; - /* Zombies don't count! */ if (is_chan_zombie(c)) continue; @@ -587,9 +568,10 @@ static void bad_gossip_order(const u8 *msg, const char *details) { status_peer_debug(source_peer, - "Bad gossip order: %s before announcement %s", + "Bad gossip order: %s before announcement %s from %s", peer_wire_name(fromwire_peektype(msg)), - details); + details, + source_peer ? type_to_string(tmpctx, struct node_id, source_peer) : "local"); } struct chan *new_chan(struct routing_state *rstate, @@ -636,17 +618,6 @@ struct chan *new_chan(struct routing_state *rstate, return chan; } -/* Checks that key is valid, and signed this hash */ -static bool check_signed_hash_nodeid(const struct sha256_double *hash, - const secp256k1_ecdsa_signature *signature, - const struct node_id *id) -{ - struct pubkey key; - - return pubkey_from_node_id(&key, id) - && check_signed_hash(hash, signature, &key); -} - /* Verify the signature of a channel_update message */ static u8 *check_channel_update(const tal_t *ctx, const struct node_id *node_id, @@ -759,11 +730,9 @@ static void catch_node_announcement(const tal_t *ctx, struct pending_node_announce *pna; struct node *node; - /* No need if we already know about the node. We might, however, only - * know about it because it's a peer (maybe with private or - * not-yet-announced channels), so check for that too. */ + /* No need if we already know about the node. */ node = get_node(rstate, nodeid); - if (node && node_has_public_channels(node)) + if (node) return; /* We can have multiple channels announced at same time for nodes; @@ -857,7 +826,6 @@ static void add_channel_announce_to_broadcast(struct routing_state *rstate, u32 index) { u8 *addendum = towire_gossip_store_channel_amount(tmpctx, chan->sat); - bool is_local = local_direction(rstate, chan, NULL); chan->bcast.timestamp = timestamp; /* 0, unless we're loading from store */ @@ -871,35 +839,24 @@ static void add_channel_announce_to_broadcast(struct routing_state *rstate, false, false, addendum); - rstate->local_channel_announced |= is_local; } static void delete_chan_messages_from_store(struct routing_state *rstate, struct chan *chan) { - int update_type, announcment_type; - - if (is_chan_public(chan)) { - update_type = WIRE_CHANNEL_UPDATE; - announcment_type = WIRE_CHANNEL_ANNOUNCEMENT; - } else { - update_type = WIRE_GOSSIP_STORE_PRIVATE_UPDATE; - announcment_type = WIRE_GOSSIP_STORE_PRIVATE_CHANNEL; - } - /* If these aren't in the store, these are noops. */ gossip_store_delete(rstate->gs, - &chan->bcast, announcment_type); + &chan->bcast, WIRE_CHANNEL_ANNOUNCEMENT); if (chan->half[0].rgraph.index != chan->half[0].bcast.index) gossip_store_delete(rstate->gs, - &chan->half[0].rgraph, update_type); + &chan->half[0].rgraph, WIRE_CHANNEL_UPDATE); gossip_store_delete(rstate->gs, - &chan->half[0].bcast, update_type); + &chan->half[0].bcast, WIRE_CHANNEL_UPDATE); if (chan->half[1].rgraph.index != chan->half[1].bcast.index) gossip_store_delete(rstate->gs, - &chan->half[1].rgraph, update_type); + &chan->half[1].rgraph, WIRE_CHANNEL_UPDATE); gossip_store_delete(rstate->gs, - &chan->half[1].bcast, update_type); + &chan->half[1].bcast, WIRE_CHANNEL_UPDATE); } static void remove_channel_from_store(struct routing_state *rstate, @@ -919,7 +876,6 @@ bool routing_add_channel_announcement(struct routing_state *rstate, u32 index, const struct node_id *source_peer) { - struct chan *oldchan; secp256k1_ecdsa_signature node_signature_1, node_signature_2; secp256k1_ecdsa_signature bitcoin_signature_1, bitcoin_signature_2; u8 *features; @@ -930,7 +886,6 @@ bool routing_add_channel_announcement(struct routing_state *rstate, struct pubkey bitcoin_key_1; struct pubkey bitcoin_key_2; struct unupdated_channel *uc; - const u8 *private_updates[2] = { NULL, NULL }; /* Make sure we own msg, even if we don't save it. */ if (taken(msg)) @@ -942,40 +897,6 @@ bool routing_add_channel_announcement(struct routing_state *rstate, &scid, &node_id_1, &node_id_2, &bitcoin_key_1, &bitcoin_key_2)) return false; - /* The channel may already exist if it was non-public from - * local_add_channel(); normally we don't accept new - * channel_announcements. See handle_channel_announcement. */ - oldchan = get_channel(rstate, &scid); - - /* private updates will exist in the store before the announce: we - * can't index those for broadcast since they would predate it, so we - * add fresh ones. */ - if (oldchan) { - /* If this was in the gossip_store, gossip_store is bad! */ - if (index) { - status_broken("gossip_store channel_announce" - " %u replaces %u!", - index, oldchan->bcast.index); - return false; - } - - /* Reload any private updates */ - if (oldchan->half[0].bcast.index) - private_updates[0] - = gossip_store_get_private_update(NULL, - rstate->gs, - oldchan->half[0].bcast.index); - if (oldchan->half[1].bcast.index) - private_updates[1] - = gossip_store_get_private_update(NULL, - rstate->gs, - oldchan->half[1].bcast.index); - - /* We don't delete it from store until *after* we've put the - * other one in! */ - uintmap_del(&rstate->chanmap, oldchan->scid.u64); - } - uc = tal(rstate, struct unupdated_channel); uc->channel_announce = tal_dup_talarr(uc, u8, msg); uc->added = gossip_time_now(rstate); @@ -992,23 +913,6 @@ bool routing_add_channel_announcement(struct routing_state *rstate, catch_node_announcement(uc, rstate, &node_id_1); catch_node_announcement(uc, rstate, &node_id_2); - /* If we had private updates, they'll immediately create the channel. */ - if (private_updates[0]) - routing_add_channel_update(rstate, take(private_updates[0]), 0, - source_peer, false, false, false); - if (private_updates[1]) - routing_add_channel_update(rstate, take(private_updates[1]), 0, - source_peer, false, false, false); - - /* Now we can finish cleanup of gossip store, so there's no window where - * channel (or nodes) vanish. */ - if (oldchan) { - /* Mark private messages deleted, but don't tombstone the channel! */ - delete_chan_messages_from_store(rstate, oldchan); - free_chans_from_node(rstate, oldchan); - tal_free(oldchan); - } - return true; } @@ -1082,7 +986,7 @@ u8 *handle_channel_announcement(struct routing_state *rstate, /* Check if we know the channel already (no matter in what * state, we stop here if yes). */ chan = get_channel(rstate, &pending->short_channel_id); - if (chan != NULL && is_chan_public(chan)) { + if (chan != NULL) { SUPERVERBOSE("%s: %s already has public channel", __func__, type_to_string(tmpctx, struct short_channel_id, @@ -1324,16 +1228,13 @@ static void update_pending(struct pending_cannouncement *pending, } static void delete_spam_update(struct routing_state *rstate, - struct half_chan *hc, - bool update_is_public) + struct half_chan *hc) { /* Spam updates will have a unique rgraph index */ if (hc->rgraph.index == hc->bcast.index) return; gossip_store_delete(rstate->gs, &hc->rgraph, - update_is_public - ? WIRE_CHANNEL_UPDATE - : WIRE_GOSSIP_STORE_PRIVATE_UPDATE); + WIRE_CHANNEL_UPDATE); hc->rgraph.index = hc->bcast.index; hc->rgraph.timestamp = hc->bcast.timestamp; } @@ -1348,14 +1249,14 @@ static bool is_chan_dying(struct routing_state *rstate, return false; } -static void tell_lightningd_peer_update(struct routing_state *rstate, - const struct node_id *source_peer, - struct short_channel_id scid, - u32 fee_base_msat, - u32 fee_ppm, - u16 cltv_delta, - struct amount_msat htlc_minimum, - struct amount_msat htlc_maximum) +void tell_lightningd_peer_update(struct routing_state *rstate, + const struct node_id *source_peer, + struct short_channel_id scid, + u32 fee_base_msat, + u32 fee_ppm, + u16 cltv_delta, + struct amount_msat htlc_minimum, + struct amount_msat htlc_maximum) { struct peer_update remote_update; u8* msg; @@ -1369,6 +1270,24 @@ static void tell_lightningd_peer_update(struct routing_state *rstate, daemon_conn_send(rstate->daemon->master, take(msg)); } +/* Is this channel_update different from prev (not sigs and timestamps)? */ +static bool cupdate_different(struct gossip_store *gs, + const struct half_chan *hc, + const u8 *cupdate) +{ + const u8 *oparts[2], *nparts[2]; + size_t osizes[2], nsizes[2]; + const u8 *orig; + + /* Get last one we have. */ + orig = gossip_store_get(tmpctx, gs, hc->bcast.index); + get_cupdate_parts(orig, oparts, osizes); + get_cupdate_parts(cupdate, nparts, nsizes); + + return !memeq(oparts[0], osizes[0], nparts[0], nsizes[0]) + || !memeq(oparts[1], osizes[1], nparts[1], nsizes[1]); +} + bool routing_add_channel_update(struct routing_state *rstate, const u8 *update TAKES, u32 index, @@ -1501,11 +1420,8 @@ bool routing_add_channel_update(struct routing_state *rstate, return true; } - /* Make sure it's not spamming us (private channel - * updates are never considered spam, nor is anything - * we send ourselves!) */ - if (is_chan_public(chan) - && !local_direction(rstate, chan, NULL) + /* Make sure it's not spamming us */ + if (!local_direction(rstate, chan, NULL) && !ratelimit(rstate, &hc->tokens, hc->bcast.timestamp, timestamp)) { status_peer_debug(source_peer, @@ -1527,12 +1443,10 @@ bool routing_add_channel_update(struct routing_state *rstate, spam = true; /* Delete any prior entries (noop if they don't exist) */ - delete_spam_update(rstate, hc, is_chan_public(chan)); + delete_spam_update(rstate, hc); if (!spam) gossip_store_delete(rstate->gs, &hc->bcast, - is_chan_public(chan) - ? WIRE_CHANNEL_UPDATE - : WIRE_GOSSIP_STORE_PRIVATE_UPDATE); + WIRE_CHANNEL_UPDATE); /* Update timestamp(s) */ hc->rgraph.timestamp = timestamp; @@ -1545,8 +1459,9 @@ bool routing_add_channel_update(struct routing_state *rstate, tell_lightningd_peer_update(rstate, /* Note: we can get public * channel_updates from other than - * direct peer! */ - is_chan_public(chan) ? NULL : source_peer, + * direct peer! So tell lightningd + * to trust us. */ + NULL, short_channel_id, fee_base_msat, fee_proportional_millionths, expiry, htlc_minimum, @@ -1564,23 +1479,6 @@ bool routing_add_channel_update(struct routing_state *rstate, uc->channel_announce, timestamp, uc->index); - } else if (!is_chan_public(chan)) { - /* For private channels, we get updates without an announce: don't - * broadcast them! But save local ones to store anyway. */ - assert(local_direction(rstate, chan, NULL)); - /* Don't save if we're loading from store */ - if (!index) { - hc->bcast.index - = gossip_store_add_private_update(rstate->gs, - update); - /* No need to separately track spam for private - * channels. */ - hc->rgraph.index = hc->bcast.index; - } else { - hc->bcast.index = index; - hc->rgraph.index = index; - } - return true; } /* Handle resurrection of zombie channels if the other side of the @@ -1607,9 +1505,7 @@ bool routing_add_channel_update(struct routing_state *rstate, zombie_addendum = gossip_store_get(tmpctx, rstate->gs, chan->bcast.index + offset); gossip_store_delete(rstate->gs, &chan->bcast, - is_chan_public(chan) - ? WIRE_CHANNEL_ANNOUNCEMENT - : WIRE_GOSSIP_STORE_PRIVATE_CHANNEL); + WIRE_CHANNEL_ANNOUNCEMENT); chan->bcast.index = gossip_store_add(rstate->gs, zombie_announcement, chan->bcast.timestamp, @@ -1625,14 +1521,10 @@ bool routing_add_channel_update(struct routing_state *rstate, zombie_update[1] = gossip_store_get(tmpctx, rstate->gs, chan->half[!direction].rgraph.index); gossip_store_delete(rstate->gs, &chan->half[!direction].rgraph, - is_chan_public(chan) - ? WIRE_CHANNEL_UPDATE - : WIRE_GOSSIP_STORE_PRIVATE_UPDATE); + WIRE_CHANNEL_UPDATE); } gossip_store_delete(rstate->gs, &chan->half[!direction].bcast, - is_chan_public(chan) - ? WIRE_CHANNEL_UPDATE - : WIRE_GOSSIP_STORE_PRIVATE_UPDATE); + WIRE_CHANNEL_UPDATE); chan->half[!direction].bcast.index = gossip_store_add(rstate->gs, zombie_update[0], chan->half[!direction].bcast.timestamp, @@ -1791,6 +1683,18 @@ u8 *handle_channel_update(struct routing_state *rstate, const u8 *update TAKES, owner = get_channel_owner(rstate, &short_channel_id, direction); if (!owner) { + /* This may be a local channel we don't know about. If it's from a peer, + * check signature assuming it's from that peer, and if it's valid, hand to ld */ + if (source_peer + && check_channel_update(tmpctx, source_peer, &signature, serialized) == NULL) { + tell_lightningd_peer_update(rstate, source_peer, + short_channel_id, fee_base_msat, + fee_proportional_millionths, + expiry, htlc_minimum, + htlc_maximum); + return NULL; + } + if (unknown_scid) *unknown_scid = short_channel_id; bad_gossip_order(serialized, @@ -1822,6 +1726,84 @@ u8 *handle_channel_update(struct routing_state *rstate, const u8 *update TAKES, return NULL; } +/* 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[3], + size_t sizes[3]) +{ + size_t len, ad_len; + const u8 *flen, *ad_start; + + /* BOLT #7: + * + * 1. type: 257 (`node_announcement`) + * 2. data: + * * [`signature`:`signature`] + * * [`u16`:`flen`] + * * [`flen*byte`:`features`] + * * [`u32`:`timestamp`] + *... + */ + /* Note: 2 bytes for `type` field */ + /* We already checked it's valid before accepting */ + assert(tal_count(node_announcement) > 2 + 64); + parts[0] = node_announcement + 2 + 64; + + /* Read flen to get size */ + flen = parts[0]; + len = tal_count(node_announcement) - (2 + 64); + 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; + + /* 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)? */ +static bool nannounce_different(struct gossip_store *gs, + const struct node *node, + const u8 *nannounce) +{ + const u8 *oparts[3], *nparts[3]; + size_t osizes[3], nsizes[3]; + const u8 *orig; + + /* Get last one we have. */ + orig = gossip_store_get(tmpctx, gs, node->bcast.index); + get_nannounce_parts(orig, oparts, osizes); + get_nannounce_parts(nannounce, nparts, nsizes); + + return !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]); +} + bool routing_add_node_announcement(struct routing_state *rstate, const u8 *msg TAKES, u32 index, @@ -1905,7 +1887,6 @@ bool routing_add_node_announcement(struct routing_state *rstate, } if (node->bcast.index) { - bool only_tlv_diff; u32 redundant_time; /* The gossip_store should contain a single broadcastable entry @@ -1933,8 +1914,7 @@ bool routing_add_node_announcement(struct routing_state *rstate, /* Allow redundant updates once a day (faster in dev-fast-gossip-prune mode) */ redundant_time = GOSSIP_PRUNE_INTERVAL(rstate->dev_fast_gossip_prune) / 14; if (timestamp < node->bcast.timestamp + redundant_time - && !nannounce_different(rstate->gs, node, msg, - &only_tlv_diff)) { + && !nannounce_different(rstate->gs, node, msg)) { SUPERVERBOSE( "Ignoring redundant nannounce for %s" " (last %u, now %u)", @@ -2109,9 +2089,6 @@ void route_prune(struct routing_state *rstate) for (struct chan *chan = uintmap_first(&rstate->chanmap, &idx); chan; chan = uintmap_after(&rstate->chanmap, &idx)) { - /* Local-only? Don't prune. */ - if (!is_chan_public(chan)) - continue; /* These have been pruned already */ if (is_chan_zombie(chan)) continue; @@ -2126,6 +2103,11 @@ void route_prune(struct routing_state *rstate) || chan->half[0].bcast.timestamp < highwater || !is_halfchan_defined(&chan->half[1]) || chan->half[1].bcast.timestamp < highwater) { + if (local_direction(rstate, chan, NULL)) + status_unusual("Pruning local channel %s from gossip_store: not refreshed in over two weeks", + type_to_string(tmpctx, struct short_channel_id, + &chan->scid)); + status_debug( "Pruning channel %s from network view (ages %"PRIu64" and %"PRIu64"s)", type_to_string(tmpctx, struct short_channel_id, @@ -2157,78 +2139,6 @@ void route_prune(struct routing_state *rstate) } } -bool routing_add_private_channel(struct routing_state *rstate, - const struct node_id *id, - struct amount_sat capacity, - const u8 *chan_ann, u64 index) -{ - struct short_channel_id scid; - struct node_id node_id[2]; - struct pubkey ignorekey; - struct chan *chan; - u8 *features; - secp256k1_ecdsa_signature ignoresig; - struct bitcoin_blkid chain_hash; - - if (!fromwire_channel_announcement(tmpctx, chan_ann, - &ignoresig, - &ignoresig, - &ignoresig, - &ignoresig, - &features, - &chain_hash, - &scid, - &node_id[0], - &node_id[1], - &ignorekey, - &ignorekey)) - return false; - - /* Happens on channeld restart. */ - if (get_channel(rstate, &scid)) - return true; - - /* Make sure this id (if any) was allowed to create this */ - if (id) { - struct node_id expected[2]; - int cmp = node_id_cmp(&rstate->daemon->id, id); - - if (cmp < 0) { - expected[0] = rstate->daemon->id; - expected[1] = *id; - } else if (cmp > 0) { - expected[0] = *id; - expected[1] = rstate->daemon->id; - } else { - /* lightningd sets id, so this is fatal */ - status_failed(STATUS_FAIL_MASTER_IO, - "private_channel peer was us?"); - } - - if (!node_id_eq(&node_id[0], &expected[0]) - || !node_id_eq(&node_id[1], &expected[1])) { - status_peer_broken(id, "private channel %s<->%s invalid", - type_to_string(tmpctx, struct node_id, - &node_id[0]), - type_to_string(tmpctx, struct node_id, - &node_id[1])); - return false; - } - } - - /* Create new (unannounced) channel */ - chan = new_chan(rstate, &scid, &node_id[0], &node_id[1], capacity); - if (!index) { - u8 *msg = towire_gossip_store_private_channel(tmpctx, - capacity, - chan_ann); - index = gossip_store_add(rstate->gs, msg, 0, false, false, false, - NULL); - } - chan->bcast.index = index; - return true; -} - struct timeabs gossip_time_now(const struct routing_state *rstate) { if (rstate->dev_gossip_time) diff --git a/gossipd/routing.h b/gossipd/routing.h index b2c2dd5f323d..71062b65837f 100644 --- a/gossipd/routing.h +++ b/gossipd/routing.h @@ -52,30 +52,9 @@ struct chan { struct amount_sat sat; }; -/* Shadow structure for local channels: owned by the chan above, but kept - * separately to keep `struct chan` minimal since there may be millions - * of non-local channels. */ -struct local_chan { - struct chan *chan; - int direction; - - /* We soft-disable local channels when a peer disconnects */ - bool local_disabled; - - /* Timer if we're deferring an update. */ - struct oneshot *channel_update_timer; -}; - /* Use this instead of tal_free(chan)! */ void free_chan(struct routing_state *rstate, struct chan *chan); -/* A local channel can exist which isn't announced: we abuse timestamp - * to indicate this. */ -static inline bool is_chan_public(const struct chan *chan) -{ - return chan->bcast.timestamp != 0; -} - static inline bool is_halfchan_defined(const struct half_chan *hc) { return hc->bcast.index != 0; @@ -217,9 +196,6 @@ struct routing_state { * we haven't got a channel_update for these yet. */ UINTMAP(struct unupdated_channel *) unupdated_chanmap; - /* Has one of our own channels been announced? */ - bool local_channel_announced; - /* Cache for txout queries that failed. Allows us to skip failed * checks if we get another announcement for the same scid. */ size_t num_txout_failures; @@ -379,19 +355,6 @@ bool routing_add_node_announcement(struct routing_state *rstate, bool *was_unknown, bool force_spam_flag); - -/** - * Add a local channel. - * - * Entrypoint to add a local channel that was not learned through gossip. This - * is the case for private channels or channels that have not yet reached - * `announce_depth`. - */ -bool routing_add_private_channel(struct routing_state *rstate, - const struct node_id *id, - struct amount_sat sat, - const u8 *chan_ann, u64 index); - /** * Get the local time. * @@ -435,4 +398,14 @@ bool node_has_broadcastable_channels(const struct node *node); const char *unfinalized_entries(const tal_t *ctx, struct routing_state *rstate); void remove_all_gossip(struct routing_state *rstate); + +/* We have an update for one of our channels (or unknown). */ +void tell_lightningd_peer_update(struct routing_state *rstate, + const struct node_id *source_peer, + struct short_channel_id scid, + u32 fee_base_msat, + u32 fee_ppm, + u16 cltv_delta, + struct amount_msat htlc_minimum, + struct amount_msat htlc_maximum); #endif /* LIGHTNING_GOSSIPD_ROUTING_H */ diff --git a/gossipd/seeker.c b/gossipd/seeker.c index d0b2cb29d1b8..159b0a2c1cb9 100644 --- a/gossipd/seeker.c +++ b/gossipd/seeker.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -453,10 +454,6 @@ static bool get_unannounced_nodes(const tal_t *ctx, for (struct chan *c = uintmap_first(&rstate->chanmap, &offset); c; c = uintmap_after(&rstate->chanmap, &offset)) { - /* Local-only? Don't ask. */ - if (!is_chan_public(c)) - continue; - if (c->nodes[0]->bcast.index && c->nodes[1]->bcast.index) continue; @@ -979,3 +976,8 @@ void seeker_peer_gone(struct seeker *seeker, const struct peer *peer) if (seeker->preferred_peer == peer) seeker->preferred_peer = NULL; } + +void dev_seeker_memleak(struct htable *memtable, struct seeker *seeker) +{ + memleak_scan_uintmap(memtable, &seeker->stale_scids); +} diff --git a/gossipd/seeker.h b/gossipd/seeker.h index dce637935fce..2edd2662355d 100644 --- a/gossipd/seeker.h +++ b/gossipd/seeker.h @@ -25,4 +25,6 @@ bool add_unknown_scid(struct seeker *seeker, void seeker_peer_gone(struct seeker *seeker, const struct peer *peer); + +void dev_seeker_memleak(struct htable *memtable, struct seeker *seeker); #endif /* LIGHTNING_GOSSIPD_SEEKER_H */ diff --git a/gossipd/test/run-check_channel_announcement.c b/gossipd/test/run-check_channel_announcement.c index a299d0a35830..95eb5a2a0ede 100644 --- a/gossipd/test/run-check_channel_announcement.c +++ b/gossipd/test/run-check_channel_announcement.c @@ -54,22 +54,19 @@ bool blinding_next_pubkey(const struct pubkey *pk UNNEEDED, const struct sha256 *h UNNEEDED, struct pubkey *next UNNEEDED) { fprintf(stderr, "blinding_next_pubkey called!\n"); abort(); } -/* Generated stub for cupdate_different */ -bool cupdate_different(struct gossip_store *gs UNNEEDED, - const struct half_chan *hc UNNEEDED, - const u8 *cupdate UNNEEDED) -{ fprintf(stderr, "cupdate_different called!\n"); abort(); } /* Generated stub for daemon_conn_send */ void daemon_conn_send(struct daemon_conn *dc UNNEEDED, const u8 *msg UNNEEDED) { fprintf(stderr, "daemon_conn_send called!\n"); abort(); } +/* Generated stub for get_cupdate_parts */ +void get_cupdate_parts(const u8 *channel_update UNNEEDED, + const u8 *parts[2] UNNEEDED, + size_t sizes[2]) +{ fprintf(stderr, "get_cupdate_parts called!\n"); abort(); } /* Generated stub for gossip_store_add */ u64 gossip_store_add(struct gossip_store *gs UNNEEDED, const u8 *gossip_msg UNNEEDED, u32 timestamp UNNEEDED, bool zombie UNNEEDED, bool spam UNNEEDED, bool dying UNNEEDED, const u8 *addendum UNNEEDED) { fprintf(stderr, "gossip_store_add called!\n"); abort(); } -/* Generated stub for gossip_store_add_private_update */ -u64 gossip_store_add_private_update(struct gossip_store *gs UNNEEDED, const u8 *update UNNEEDED) -{ fprintf(stderr, "gossip_store_add_private_update called!\n"); abort(); } /* Generated stub for gossip_store_delete */ void gossip_store_delete(struct gossip_store *gs UNNEEDED, struct broadcastable *bcast UNNEEDED, @@ -80,11 +77,6 @@ const u8 *gossip_store_get(const tal_t *ctx UNNEEDED, struct gossip_store *gs UNNEEDED, u64 offset UNNEEDED) { fprintf(stderr, "gossip_store_get called!\n"); abort(); } -/* Generated stub for gossip_store_get_private_update */ -const u8 *gossip_store_get_private_update(const tal_t *ctx UNNEEDED, - struct gossip_store *gs UNNEEDED, - u64 offset UNNEEDED) -{ fprintf(stderr, "gossip_store_get_private_update called!\n"); abort(); } /* Generated stub for gossip_store_mark_channel_deleted */ void gossip_store_mark_channel_deleted(struct gossip_store *gs UNNEEDED, const struct short_channel_id *scid UNNEEDED) @@ -106,12 +98,6 @@ void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable * /* Generated stub for memleak_scan_intmap_ */ void memleak_scan_intmap_(struct htable *memtable UNNEEDED, const struct intmap *m UNNEEDED) { fprintf(stderr, "memleak_scan_intmap_ called!\n"); abort(); } -/* Generated stub for nannounce_different */ -bool nannounce_different(struct gossip_store *gs UNNEEDED, - const struct node *node 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, const tal_t *ctx UNNEEDED, @@ -126,10 +112,6 @@ void peer_supplied_good_gossip(struct daemon *daemon UNNEEDED, const struct node_id *source_peer UNNEEDED, size_t amount UNNEEDED) { fprintf(stderr, "peer_supplied_good_gossip 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, diff --git a/gossipd/test/run-check_node_announcement.c b/gossipd/test/run-check_node_announcement.c deleted file mode 100644 index c5a024ccb082..000000000000 --- a/gossipd/test/run-check_node_announcement.c +++ /dev/null @@ -1,158 +0,0 @@ -#include "config.h" -#include "../gossip_generation.c" -#include -#include -#include -#include -#include -#include -#include - -/* AUTOGENERATED MOCKS START */ -/* Generated stub for blinding_hash_e_and_ss */ -void blinding_hash_e_and_ss(const struct pubkey *e UNNEEDED, - const struct secret *ss UNNEEDED, - struct sha256 *sha UNNEEDED) -{ fprintf(stderr, "blinding_hash_e_and_ss called!\n"); abort(); } -/* Generated stub for blinding_next_privkey */ -bool blinding_next_privkey(const struct privkey *e UNNEEDED, - const struct sha256 *h UNNEEDED, - struct privkey *next UNNEEDED) -{ fprintf(stderr, "blinding_next_privkey called!\n"); abort(); } -/* Generated stub for blinding_next_pubkey */ -bool blinding_next_pubkey(const struct pubkey *pk UNNEEDED, - const struct sha256 *h UNNEEDED, - struct pubkey *next UNNEEDED) -{ fprintf(stderr, "blinding_next_pubkey called!\n"); abort(); } -/* Generated stub for daemon_conn_send */ -void daemon_conn_send(struct daemon_conn *dc UNNEEDED, const u8 *msg UNNEEDED) -{ fprintf(stderr, "daemon_conn_send called!\n"); abort(); } -/* 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 fromwire_gossipd_local_channel_update */ -bool fromwire_gossipd_local_channel_update(const void *p UNNEEDED, struct node_id *id UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED, bool *enable 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, bool *public UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_local_channel_update called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_used_local_channel_update */ -bool fromwire_gossipd_used_local_channel_update(const void *p UNNEEDED, struct short_channel_id *scid UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_used_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, - const struct node_id *source_peer TAKES 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_ann UNNEEDED, - const struct node_id *source_peer TAKES UNNEEDED, - bool *was_unknown UNNEEDED) -{ fprintf(stderr, "handle_node_announcement called!\n"); abort(); } -/* Generated stub for master_badmsg */ -void master_badmsg(u32 type_expected UNNEEDED, const u8 *msg) -{ fprintf(stderr, "master_badmsg 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 node_has_broadcastable_channels */ -bool node_has_broadcastable_channels(const struct node *node UNNEEDED) -{ fprintf(stderr, "node_has_broadcastable_channels 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_gossipd_got_local_channel_update */ -u8 *towire_gossipd_got_local_channel_update(const tal_t *ctx UNNEEDED, const struct short_channel_id *scid UNNEEDED, const u8 *channel_update UNNEEDED) -{ fprintf(stderr, "towire_gossipd_got_local_channel_update 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 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-crc32_of_update.c b/gossipd/test/run-crc32_of_update.c index 2a16407d878a..c14c5f360cf5 100644 --- a/gossipd/test/run-crc32_of_update.c +++ b/gossipd/test/run-crc32_of_update.c @@ -2,7 +2,6 @@ int unused_main(int argc, char *argv[]); #define main unused_main #include "../queries.c" -#include "../gossip_generation.c" #undef main #include #include @@ -28,9 +27,6 @@ bool blinding_next_pubkey(const struct pubkey *pk UNNEEDED, const struct sha256 *h UNNEEDED, struct pubkey *next UNNEEDED) { fprintf(stderr, "blinding_next_pubkey called!\n"); abort(); } -/* Generated stub for daemon_conn_send */ -void daemon_conn_send(struct daemon_conn *dc UNNEEDED, const u8 *msg UNNEEDED) -{ fprintf(stderr, "daemon_conn_send called!\n"); abort(); } /* Generated stub for daemon_conn_wake */ void daemon_conn_wake(struct daemon_conn *dc UNNEEDED) { fprintf(stderr, "daemon_conn_wake called!\n"); abort(); } @@ -45,9 +41,6 @@ bigsize_t *decode_scid_query_flags(const tal_t *ctx UNNEEDED, /* Generated stub for decode_short_ids */ struct short_channel_id *decode_short_ids(const tal_t *ctx UNNEEDED, const u8 *encoded UNNEEDED) { fprintf(stderr, "decode_short_ids called!\n"); abort(); } -/* 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 first_random_peer */ struct peer *first_random_peer(struct daemon *daemon UNNEEDED, struct peer_node_id_map_iter *it UNNEEDED) @@ -55,18 +48,6 @@ struct peer *first_random_peer(struct daemon *daemon UNNEEDED, /* Generated stub for fromwire_gossipd_dev_set_max_scids_encode_size */ bool fromwire_gossipd_dev_set_max_scids_encode_size(const void *p UNNEEDED, u32 *max UNNEEDED) { fprintf(stderr, "fromwire_gossipd_dev_set_max_scids_encode_size called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_local_channel_update */ -bool fromwire_gossipd_local_channel_update(const void *p UNNEEDED, struct node_id *id UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED, bool *enable 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, bool *public UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_local_channel_update called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_used_local_channel_update */ -bool fromwire_gossipd_used_local_channel_update(const void *p UNNEEDED, struct short_channel_id *scid UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_used_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) @@ -76,37 +57,14 @@ const u8 *gossip_store_get(const tal_t *ctx UNNEEDED, struct gossip_store *gs UNNEEDED, u64 offset UNNEEDED) { fprintf(stderr, "gossip_store_get 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, - const struct node_id *source_peer TAKES 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_ann UNNEEDED, - const struct node_id *source_peer TAKES UNNEEDED, - bool *was_unknown UNNEEDED) -{ fprintf(stderr, "handle_node_announcement called!\n"); abort(); } /* Generated stub for master_badmsg */ void master_badmsg(u32 type_expected UNNEEDED, const u8 *msg) { fprintf(stderr, "master_badmsg 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 next_random_peer */ struct peer *next_random_peer(struct daemon *daemon UNNEEDED, const struct peer *first UNNEEDED, struct peer_node_id_map_iter *it UNNEEDED) { fprintf(stderr, "next_random_peer called!\n"); abort(); } -/* Generated stub for node_has_broadcastable_channels */ -bool node_has_broadcastable_channels(const struct node *node UNNEEDED) -{ fprintf(stderr, "node_has_broadcastable_channels called!\n"); abort(); } /* Generated stub for peer_supplied_good_gossip */ void peer_supplied_good_gossip(struct daemon *daemon UNNEEDED, const struct node_id *source_peer UNNEEDED, @@ -119,36 +77,17 @@ void queue_peer_from_store(struct peer *peer UNNEEDED, /* 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_gossipd_got_local_channel_update */ -u8 *towire_gossipd_got_local_channel_update(const tal_t *ctx UNNEEDED, const struct short_channel_id *scid UNNEEDED, const u8 *channel_update UNNEEDED) -{ fprintf(stderr, "towire_gossipd_got_local_channel_update 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_warningfmt */ u8 *towire_warningfmt(const tal_t *ctx UNNEEDED, const struct channel_id *channel UNNEEDED, const char *fmt UNNEEDED, ...) { fprintf(stderr, "towire_warningfmt 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 */ int main(int argc, char *argv[]) diff --git a/gossipd/test/run-extended-info.c b/gossipd/test/run-extended-info.c index ec7b3187628b..b38d990d753d 100644 --- a/gossipd/test/run-extended-info.c +++ b/gossipd/test/run-extended-info.c @@ -52,11 +52,6 @@ struct peer *first_random_peer(struct daemon *daemon UNNEEDED, /* Generated stub for fromwire_gossipd_dev_set_max_scids_encode_size */ bool fromwire_gossipd_dev_set_max_scids_encode_size(const void *p UNNEEDED, u32 *max UNNEEDED) { fprintf(stderr, "fromwire_gossipd_dev_set_max_scids_encode_size called!\n"); abort(); } -/* Generated stub for get_cupdate_parts */ -void get_cupdate_parts(const u8 *channel_update UNNEEDED, - const u8 *parts[2] UNNEEDED, - size_t sizes[2]) -{ fprintf(stderr, "get_cupdate_parts called!\n"); abort(); } /* Generated stub for get_node */ struct node *get_node(struct routing_state *rstate UNNEEDED, const struct node_id *id UNNEEDED) diff --git a/gossipd/test/run-next_block_range.c b/gossipd/test/run-next_block_range.c index dcee25621b9f..dfebada2e481 100644 --- a/gossipd/test/run-next_block_range.c +++ b/gossipd/test/run-next_block_range.c @@ -30,6 +30,9 @@ bool blinding_next_pubkey(const struct pubkey *pk UNNEEDED, struct peer *first_random_peer(struct daemon *daemon UNNEEDED, struct peer_node_id_map_iter *it UNNEEDED) { fprintf(stderr, "first_random_peer called!\n"); abort(); } +/* Generated stub for memleak_scan_intmap_ */ +void memleak_scan_intmap_(struct htable *memtable UNNEEDED, const struct intmap *m UNNEEDED) +{ fprintf(stderr, "memleak_scan_intmap_ called!\n"); abort(); } /* Generated stub for new_reltimer_ */ struct oneshot *new_reltimer_(struct timers *timers UNNEEDED, const tal_t *ctx UNNEEDED, diff --git a/gossipd/test/run-txout_failure.c b/gossipd/test/run-txout_failure.c index 21c9290c8da8..d9047c994fda 100644 --- a/gossipd/test/run-txout_failure.c +++ b/gossipd/test/run-txout_failure.c @@ -25,22 +25,19 @@ bool blinding_next_pubkey(const struct pubkey *pk UNNEEDED, const struct sha256 *h UNNEEDED, struct pubkey *next UNNEEDED) { fprintf(stderr, "blinding_next_pubkey called!\n"); abort(); } -/* Generated stub for cupdate_different */ -bool cupdate_different(struct gossip_store *gs UNNEEDED, - const struct half_chan *hc UNNEEDED, - const u8 *cupdate UNNEEDED) -{ fprintf(stderr, "cupdate_different called!\n"); abort(); } /* Generated stub for daemon_conn_send */ void daemon_conn_send(struct daemon_conn *dc UNNEEDED, const u8 *msg UNNEEDED) { fprintf(stderr, "daemon_conn_send called!\n"); abort(); } +/* Generated stub for get_cupdate_parts */ +void get_cupdate_parts(const u8 *channel_update UNNEEDED, + const u8 *parts[2] UNNEEDED, + size_t sizes[2]) +{ fprintf(stderr, "get_cupdate_parts called!\n"); abort(); } /* Generated stub for gossip_store_add */ u64 gossip_store_add(struct gossip_store *gs UNNEEDED, const u8 *gossip_msg UNNEEDED, u32 timestamp UNNEEDED, bool zombie UNNEEDED, bool spam UNNEEDED, bool dying UNNEEDED, const u8 *addendum UNNEEDED) { fprintf(stderr, "gossip_store_add called!\n"); abort(); } -/* Generated stub for gossip_store_add_private_update */ -u64 gossip_store_add_private_update(struct gossip_store *gs UNNEEDED, const u8 *update UNNEEDED) -{ fprintf(stderr, "gossip_store_add_private_update called!\n"); abort(); } /* Generated stub for gossip_store_delete */ void gossip_store_delete(struct gossip_store *gs UNNEEDED, struct broadcastable *bcast UNNEEDED, @@ -51,11 +48,6 @@ const u8 *gossip_store_get(const tal_t *ctx UNNEEDED, struct gossip_store *gs UNNEEDED, u64 offset UNNEEDED) { fprintf(stderr, "gossip_store_get called!\n"); abort(); } -/* Generated stub for gossip_store_get_private_update */ -const u8 *gossip_store_get_private_update(const tal_t *ctx UNNEEDED, - struct gossip_store *gs UNNEEDED, - u64 offset UNNEEDED) -{ fprintf(stderr, "gossip_store_get_private_update called!\n"); abort(); } /* Generated stub for gossip_store_mark_channel_deleted */ void gossip_store_mark_channel_deleted(struct gossip_store *gs UNNEEDED, const struct short_channel_id *scid UNNEEDED) @@ -74,12 +66,6 @@ void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable * /* Generated stub for memleak_scan_intmap_ */ void memleak_scan_intmap_(struct htable *memtable UNNEEDED, const struct intmap *m UNNEEDED) { fprintf(stderr, "memleak_scan_intmap_ called!\n"); abort(); } -/* Generated stub for nannounce_different */ -bool nannounce_different(struct gossip_store *gs UNNEEDED, - const struct node *node UNNEEDED, - const u8 *nannounce UNNEEDED, - bool *only_missing_tlv UNNEEDED) -{ fprintf(stderr, "nannounce_different called!\n"); abort(); } /* Generated stub for notleak_ */ void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) { fprintf(stderr, "notleak_ called!\n"); abort(); } @@ -92,10 +78,6 @@ void peer_supplied_good_gossip(struct daemon *daemon UNNEEDED, char *sanitize_error(const tal_t *ctx UNNEEDED, const u8 *errmsg UNNEEDED, struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "sanitize_error 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, diff --git a/hsmd/hsmd.c b/hsmd/hsmd.c index d557799aed52..1aec53028500 100644 --- a/hsmd/hsmd.c +++ b/hsmd/hsmd.c @@ -671,6 +671,7 @@ static struct io_plan *handle_client(struct io_conn *conn, struct client *c) case WIRE_HSMD_GET_OUTPUT_SCRIPTPUBKEY: case WIRE_HSMD_DERIVE_SECRET: case WIRE_HSMD_CANNOUNCEMENT_SIG_REQ: + case WIRE_HSMD_SIGN_ANY_CANNOUNCEMENT_REQ: case WIRE_HSMD_NODE_ANNOUNCEMENT_SIG_REQ: case WIRE_HSMD_CUPDATE_SIG_REQ: case WIRE_HSMD_SIGN_LOCAL_HTLC_TX: @@ -722,6 +723,7 @@ static struct io_plan *handle_client(struct io_conn *conn, struct client *c) case WIRE_HSMD_CHECK_PUBKEY_REPLY: case WIRE_HSMD_SIGN_ANCHORSPEND_REPLY: case WIRE_HSMD_SIGN_HTLC_TX_MINGLE_REPLY: + case WIRE_HSMD_SIGN_ANY_CANNOUNCEMENT_REPLY: return bad_req_fmt(conn, c, c->msg_in, "Received an incoming message of type %s, " "which is not a request", diff --git a/hsmd/hsmd_wire.csv b/hsmd/hsmd_wire.csv index 3b0c9c230e30..98e3bd021596 100644 --- a/hsmd/hsmd_wire.csv +++ b/hsmd/hsmd_wire.csv @@ -176,6 +176,16 @@ msgtype,hsmd_cannouncement_sig_reply,102 msgdata,hsmd_cannouncement_sig_reply,node_signature,secp256k1_ecdsa_signature, msgdata,hsmd_cannouncement_sig_reply,bitcoin_signature,secp256k1_ecdsa_signature, +msgtype,hsmd_sign_any_cannouncement_req,4 +msgdata,hsmd_sign_any_cannouncement_req,calen,u16, +msgdata,hsmd_sign_any_cannouncement_req,ca,u8,calen +msgdata,hsmd_sign_any_cannouncement_req,peerid,node_id, +msgdata,hsmd_sign_any_cannouncement_req,channel_dbid,u64, + +msgtype,hsmd_sign_any_cannouncement_reply,104 +msgdata,hsmd_sign_any_cannouncement_reply,node_signature,secp256k1_ecdsa_signature, +msgdata,hsmd_sign_any_cannouncement_reply,bitcoin_signature,secp256k1_ecdsa_signature, + msgtype,hsmd_cupdate_sig_req,3 msgdata,hsmd_cupdate_sig_req,culen,u16, msgdata,hsmd_cupdate_sig_req,cu,u8,culen diff --git a/hsmd/libhsmd.c b/hsmd/libhsmd.c index a7686ea24ed8..a6cacdb90e38 100644 --- a/hsmd/libhsmd.c +++ b/hsmd/libhsmd.c @@ -139,6 +139,7 @@ bool hsmd_check_client_capabilities(struct hsmd_client *client, case WIRE_HSMD_SIGN_ANY_LOCAL_HTLC_TX: case WIRE_HSMD_SIGN_ANCHORSPEND: case WIRE_HSMD_SIGN_HTLC_TX_MINGLE: + case WIRE_HSMD_SIGN_ANY_CANNOUNCEMENT_REQ: return (client->capabilities & HSM_PERM_MASTER) != 0; /*~ These are messages sent by the HSM so we should never receive them. */ @@ -178,6 +179,7 @@ bool hsmd_check_client_capabilities(struct hsmd_client *client, case WIRE_HSMD_CHECK_PUBKEY_REPLY: case WIRE_HSMD_SIGN_ANCHORSPEND_REPLY: case WIRE_HSMD_SIGN_HTLC_TX_MINGLE_REPLY: + case WIRE_HSMD_SIGN_ANY_CANNOUNCEMENT_REPLY: break; } return false; @@ -972,7 +974,12 @@ static u8 *handle_get_output_scriptpubkey(struct hsmd_client *c, * defined in BOLT #7, and requires *two* signatures: one from this node's key * (to prove it's from us), and one from the bitcoin key used to create the * funding transaction (to prove we own the output). */ -static u8 *handle_cannouncement_sig(struct hsmd_client *c, const u8 *msg_in) +static const char *handle_sign_cannouncement(const tal_t *ctx, + const struct node_id *peer_id, + u64 dbid, + const u8 *ca, + secp256k1_ecdsa_signature *node_sig, + secp256k1_ecdsa_signature *bitcoin_sig) { /*~ Our autogeneration code doesn't define field offsets, so we just * copy this from the spec itself. @@ -992,10 +999,7 @@ static u8 *handle_cannouncement_sig(struct hsmd_client *c, const u8 *msg_in) /* First type bytes are the msg type */ size_t offset = 2 + 256; struct privkey node_pkey; - secp256k1_ecdsa_signature node_sig, bitcoin_sig; struct sha256_double hash; - u8 *reply; - u8 *ca; struct pubkey funding_pubkey; struct privkey funding_privkey; struct secret channel_seed; @@ -1009,32 +1013,61 @@ static u8 *handle_cannouncement_sig(struct hsmd_client *c, const u8 *msg_in) * mind if you fix this for him! */ /* FIXME: We should cache these. */ - get_channel_seed(&c->id, c->dbid, &channel_seed); + get_channel_seed(peer_id, dbid, &channel_seed); derive_funding_key(&channel_seed, &funding_pubkey, &funding_privkey); + if (tal_count(ca) < offset) + return tal_fmt(ctx, "bad cannounce length %zu", tal_count(ca)); + + if (fromwire_peektype(ca) != WIRE_CHANNEL_ANNOUNCEMENT) + return tal_fmt(ctx, "Invalid channel announcement"); + + node_key(&node_pkey, NULL); + sha256_double(&hash, ca + offset, tal_count(ca) - offset); + + sign_hash(&node_pkey, &hash, node_sig); + sign_hash(&funding_privkey, &hash, bitcoin_sig); + return NULL; +} + +static u8 *handle_cannouncement_sig(struct hsmd_client *c, const u8 *msg_in) +{ + u8 *ca; + secp256k1_ecdsa_signature node_sig, bitcoin_sig; + const char *err; + /*~ fromwire_ routines which need to do allocation take a tal context * as their first field; tmpctx is good here since we won't need it * after this function. */ if (!fromwire_hsmd_cannouncement_sig_req(tmpctx, msg_in, &ca)) return hsmd_status_malformed_request(c, msg_in); - if (tal_count(ca) < offset) - return hsmd_status_bad_request_fmt( - c, msg_in, "bad cannounce length %zu", tal_count(ca)); + err = handle_sign_cannouncement(tmpctx, &c->id, c->dbid, ca, + &node_sig, &bitcoin_sig); + if (err) + return hsmd_status_bad_request_fmt(c, msg_in, "%s", err); - if (fromwire_peektype(ca) != WIRE_CHANNEL_ANNOUNCEMENT) - return hsmd_status_bad_request_fmt( - c, msg_in, "Invalid channel announcement"); + return towire_hsmd_cannouncement_sig_reply(NULL, &node_sig, &bitcoin_sig); +} - node_key(&node_pkey, NULL); - sha256_double(&hash, ca + offset, tal_count(ca) - offset); +/* This variant is used by modern lightningd to sign for a particular channel */ +static u8 *handle_any_cannouncement_sig(struct hsmd_client *c, const u8 *msg_in) +{ + u8 *ca; + struct node_id peer_id; + u64 dbid; + secp256k1_ecdsa_signature node_sig, bitcoin_sig; + const char *err; + + if (!fromwire_hsmd_sign_any_cannouncement_req(tmpctx, msg_in, &ca, &peer_id, &dbid)) + return hsmd_status_malformed_request(c, msg_in); - sign_hash(&node_pkey, &hash, &node_sig); - sign_hash(&funding_privkey, &hash, &bitcoin_sig); + err = handle_sign_cannouncement(tmpctx, &peer_id, dbid, ca, + &node_sig, &bitcoin_sig); + if (err) + return hsmd_status_bad_request_fmt(c, msg_in, "%s", err); - reply = towire_hsmd_cannouncement_sig_reply(NULL, &node_sig, - &bitcoin_sig); - return reply; + return towire_hsmd_sign_any_cannouncement_reply(NULL, &node_sig, &bitcoin_sig); } /*~ It's optional for nodes to send node_announcement, but it lets us set our @@ -2026,6 +2059,8 @@ u8 *hsmd_handle_client_message(const tal_t *ctx, struct hsmd_client *client, return handle_get_channel_basepoints(client, msg); case WIRE_HSMD_CANNOUNCEMENT_SIG_REQ: return handle_cannouncement_sig(client, msg); + case WIRE_HSMD_SIGN_ANY_CANNOUNCEMENT_REQ: + return handle_any_cannouncement_sig(client, msg); case WIRE_HSMD_NODE_ANNOUNCEMENT_SIG_REQ: return handle_sign_node_announcement(client, msg); case WIRE_HSMD_CUPDATE_SIG_REQ: @@ -2110,6 +2145,7 @@ u8 *hsmd_handle_client_message(const tal_t *ctx, struct hsmd_client *client, case WIRE_HSMD_CHECK_PUBKEY_REPLY: case WIRE_HSMD_SIGN_ANCHORSPEND_REPLY: case WIRE_HSMD_SIGN_HTLC_TX_MINGLE_REPLY: + case WIRE_HSMD_SIGN_ANY_CANNOUNCEMENT_REPLY: break; } return hsmd_status_bad_request(client, msg, "Unknown request"); diff --git a/lightningd/Makefile b/lightningd/Makefile index 4126c0dc7713..b40a7244f799 100644 --- a/lightningd/Makefile +++ b/lightningd/Makefile @@ -6,6 +6,7 @@ LIGHTNINGD_SRC := \ lightningd/chaintopology.c \ lightningd/channel.c \ lightningd/channel_control.c \ + lightningd/channel_gossip.c \ lightningd/closing_control.c \ lightningd/coin_mvts.c \ lightningd/dual_open_control.c \ @@ -15,6 +16,7 @@ LIGHTNINGD_SRC := \ lightningd/feerate.c \ lightningd/forwards.c \ lightningd/gossip_control.c \ + lightningd/gossip_generation.c \ lightningd/hsm_control.c \ lightningd/htlc_end.c \ lightningd/htlc_set.c \ diff --git a/lightningd/chaintopology.c b/lightningd/chaintopology.c index 9b67077c7c43..4b127999b8ee 100644 --- a/lightningd/chaintopology.c +++ b/lightningd/chaintopology.c @@ -854,12 +854,12 @@ void topology_add_sync_waiter_(const tal_t *ctx, static void updates_complete(struct chain_topology *topo) { if (!bitcoin_blkid_eq(&topo->tip->blkid, &topo->prev_tip)) { - /* Tell watch code to re-evaluate all txs. */ - watch_topology_changed(topo); - /* Tell lightningd about new block. */ notify_new_block(topo->bitcoind->ld, topo->tip->height); + /* Tell watch code to re-evaluate all txs. */ + watch_topology_changed(topo); + /* Maybe need to rebroadcast. */ rebroadcast_txs(topo); diff --git a/lightningd/channel.c b/lightningd/channel.c index f180e5882a7b..6b025a4e052a 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -10,13 +10,16 @@ #include #include #include +#include #include #include +#include #include #include #include #include #include +#include #include #include @@ -251,6 +254,7 @@ struct channel *new_unsaved_channel(struct peer *peer, channel->state = DUALOPEND_OPEN_INIT; channel->owner = NULL; channel->scb = NULL; + channel->reestablished = false; memset(&channel->billboard, 0, sizeof(channel->billboard)); channel->billboard.transient = tal_fmt(channel, "%s", "Empty channel init'd"); @@ -276,9 +280,10 @@ struct channel *new_unsaved_channel(struct peer *peer, = CLOSING_FEE_NEGOTIATION_STEP_UNIT_PERCENTAGE; channel->shutdown_wrong_funding = NULL; channel->closing_feerate_range = NULL; - channel->peer_update = NULL; - channel->channel_update = NULL; - channel->alias[LOCAL] = channel->alias[REMOTE] = NULL; + channel->alias[REMOTE] = NULL; + /* We don't even bother checking for clashes. */ + channel->alias[LOCAL] = tal(channel, struct short_channel_id); + randombytes_buf(channel->alias[LOCAL], sizeof(struct short_channel_id)); channel->shutdown_scriptpubkey[REMOTE] = NULL; channel->last_was_revoke = false; @@ -308,6 +313,8 @@ struct channel *new_unsaved_channel(struct peer *peer, channel->lease_commit_sig = NULL; channel->ignore_fee_limits = ld->config.ignore_fee_limits; + channel->last_stable_connection = 0; + channel->stable_conn_timer = NULL; /* No shachain yet */ channel->their_shachain.id = 0; @@ -323,6 +330,8 @@ struct channel *new_unsaved_channel(struct peer *peer, &channel->local_basepoints, &channel->local_funding_pubkey); + /* channel->channel_gossip gets populated once we know if it's public. */ + channel->channel_gossip = NULL; channel->forgets = tal_arr(channel, struct command *, 0); list_add_tail(&peer->channels, &channel->list); channel->rr_number = peer->ld->rr_counter++; @@ -397,7 +406,7 @@ struct channel *new_channel(struct peer *peer, u64 dbid, bool remote_channel_ready, /* NULL or stolen */ struct short_channel_id *scid, - struct short_channel_id *alias_local STEALS, + struct short_channel_id *alias_local TAKES, struct short_channel_id *alias_remote STEALS, struct channel_id *cid, struct amount_msat our_msat, @@ -442,7 +451,8 @@ struct channel *new_channel(struct peer *peer, u64 dbid, struct amount_msat htlc_maximum_msat, bool ignore_fee_limits, /* NULL or stolen */ - struct peer_update *peer_update STEALS) + struct peer_update *peer_update STEALS, + u64 last_stable_connection) { struct channel *channel = tal(peer->ld, struct channel); struct amount_msat htlc_min, htlc_max; @@ -455,6 +465,7 @@ struct channel *new_channel(struct peer *peer, u64 dbid, channel->peer = peer; channel->dbid = dbid; channel->unsaved_dbid = 0; + channel->reestablished = false; channel->error = NULL; channel->open_attempt = NULL; channel->openchannel_signed_cmd = NULL; @@ -508,7 +519,7 @@ struct channel *new_channel(struct peer *peer, u64 dbid, channel->our_funds = our_funds; channel->remote_channel_ready = remote_channel_ready; channel->scid = tal_steal(channel, scid); - channel->alias[LOCAL] = tal_steal(channel, alias_local); + channel->alias[LOCAL] = tal_dup_or_null(channel, struct short_channel_id, alias_local); channel->alias[REMOTE] = tal_steal(channel, alias_remote); /* Haven't gotten one yet. */ channel->cid = *cid; channel->our_msat = our_msat; @@ -568,9 +579,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->peer_update = tal_steal(channel, peer_update); channel->blockheight_states = dup_height_states(channel, height_states); - channel->channel_update = NULL; /* DB migration, for example, sets min to 0, max to large: fixup */ htlc_min = channel->channel_info.their_config.htlc_minimum; @@ -594,6 +603,10 @@ struct channel *new_channel(struct peer *peer, u64 dbid, channel->close_blockheight = NULL; channel->state_change_cause = reason; channel->ignore_fee_limits = ignore_fee_limits; + channel->last_stable_connection = last_stable_connection; + channel->stable_conn_timer = NULL; + /* Populate channel->channel_gossip */ + channel_gossip_init(channel, take(peer_update)); /* Make sure we see any spends using this key */ if (!local_shutdown_scriptpubkey) { @@ -1094,3 +1107,11 @@ channel_scid_or_local_alias(const struct channel *chan) else return chan->alias[LOCAL]; } + +const u8 *channel_update_for_error(const tal_t *ctx, + struct channel *channel) +{ + /* FIXME: Call directly from callers */ + return channel_gossip_update_for_error(ctx, channel); +} + diff --git a/lightningd/channel.h b/lightningd/channel.h index bf70c249ae9d..9798532936f8 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -141,6 +141,9 @@ struct channel { /* Is there a single subdaemon responsible for us? */ struct subd *owner; + /* Telling the world (or just our peer) about us */ + struct channel_gossip *channel_gossip; + /* History */ struct logger *log; struct billboard billboard; @@ -280,6 +283,9 @@ struct channel { /* Block height we saw closing tx at */ u32 *close_blockheight; + /* Channeld said we've successfully exchanged reestablish. */ + bool reestablished; + /* Last known state_change cause */ enum state_change state_change_cause; @@ -298,21 +304,19 @@ struct channel { /* Lease commited max part per thousandth channel fee (ppm * 1000) */ u16 lease_chan_max_ppt; - /* Channel incoming fee rates, cltv delta min/max htlc from - * peer. Used to generate route hints, blinded paths. */ - const struct peer_update *peer_update; - - /* Latest channel_update, for use in error messages. */ - u8 *channel_update; - /* `Channel-shell` of this channel * (Minimum information required to backup this channel). */ struct scb_chan *scb; /* Do we allow the peer to set any fee it wants? */ bool ignore_fee_limits; + + /* Last time we had a stable connection, if any (0 = none) */ + u64 last_stable_connection; + struct oneshot *stable_conn_timer; }; +/* Is channel owned (and should be talking to peer) */ bool channel_is_connected(const struct channel *channel); /* For v2 opens, a channel that has not yet been committed/saved to disk */ @@ -390,7 +394,8 @@ struct channel *new_channel(struct peer *peer, u64 dbid, struct amount_msat htlc_maximum_msat, bool ignore_fee_limits, /* NULL or stolen */ - struct peer_update *peer_update STEALS); + struct peer_update *peer_update STEALS, + u64 last_stable_connection); /* new_inflight - Create a new channel_inflight for a channel */ struct channel_inflight *new_inflight(struct channel *channel, @@ -788,7 +793,10 @@ void channel_set_billboard(struct channel *channel, bool perm, struct htlc_in *channel_has_htlc_in(struct channel *channel); struct htlc_out *channel_has_htlc_out(struct channel *channel); -const u8 *get_channel_update(struct channel *channel); +const u8 *channel_update_for_error(const tal_t *ctx, + struct channel *channel); struct amount_msat htlc_max_possible_send(const struct channel *channel); + + #endif /* LIGHTNING_LIGHTNINGD_CHANNEL_H */ diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index 3beb7a20181c..e1e142fad0b9 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -594,7 +595,6 @@ static enum watch_result splice_depth_cb(struct lightningd *ld, subd_send_msg(inflight->channel->owner, take(towire_channeld_funding_depth( NULL, &scid, - inflight->channel->alias[LOCAL], depth, true, txid))); } @@ -683,6 +683,10 @@ bool depthcb_update_scid(struct channel *channel, return false; } + /* No change? Great. */ + if (channel->scid && short_channel_id_eq(channel->scid, &scid)) + return true; + if (!channel->scid) { wallet_annotate_txout(ld->wallet, outpoint, TX_CHANNEL_FUNDING, channel->dbid); @@ -697,17 +701,17 @@ bool depthcb_update_scid(struct channel *channel, if (channel->minimum_depth == 0) lockin_has_completed(channel, false); - wallet_channel_save(ld->wallet, channel); - } else if (!short_channel_id_eq(channel->scid, &scid)) { + } else { /* We freaked out if required when original was * removed, so just update now */ log_info(channel->log, "Short channel id changed from %s->%s", type_to_string(tmpctx, struct short_channel_id, channel->scid), type_to_string(tmpctx, struct short_channel_id, &scid)); *channel->scid = scid; - wallet_channel_save(ld->wallet, channel); + channel_gossip_scid_changed(channel); } + wallet_channel_save(ld->wallet, channel); return true; } @@ -887,12 +891,13 @@ void channel_record_open(struct channel *channel, u32 blockheight, bool record_p void lockin_has_completed(struct channel *channel, bool record_push) { + struct lightningd *ld = channel->peer->ld; + /* Fees might have changed (and we use IMMEDIATE once we're funded), * so update now. */ - try_update_feerates(channel->peer->ld, channel); + try_update_feerates(ld, channel); - try_update_blockheight(channel->peer->ld, channel, - get_block_height(channel->peer->ld->topology)); + try_update_blockheight(ld, channel, get_block_height(ld->topology)); /* Emit an event for the channel open (or channel proposal if blockheight * is zero) */ @@ -922,10 +927,6 @@ void lockin_complete(struct channel *channel, return; } - log_debug(channel->log, "Moving channel state from %s to %s", - channel_state_str(expected_state), - channel_state_str(CHANNELD_NORMAL)); - channel_set_state(channel, expected_state, CHANNELD_NORMAL, @@ -936,7 +937,8 @@ void lockin_complete(struct channel *channel, } bool channel_on_channel_ready(struct channel *channel, - struct pubkey *next_per_commitment_point) + const struct pubkey *next_per_commitment_point, + const struct short_channel_id *remote_alias) { if (channel->remote_channel_ready) { channel_internal_error(channel, @@ -945,6 +947,13 @@ bool channel_on_channel_ready(struct channel *channel, } update_per_commit_point(channel, next_per_commitment_point); + /* FIXME: we should apply this even if it changed! */ + if (channel->alias[REMOTE] == NULL) { + channel->alias[REMOTE] + = tal_dup_or_null(channel, struct short_channel_id, + remote_alias); + } + log_debug(channel->log, "Got channel_ready"); channel->remote_channel_ready = true; @@ -1034,12 +1043,11 @@ static void peer_got_channel_ready(struct channel *channel, const u8 *msg) return; } - if (!channel_on_channel_ready(channel, &next_per_commitment_point)) + if (!channel_on_channel_ready(channel, + &next_per_commitment_point, + alias_remote)) return; - if (channel->alias[REMOTE] == NULL) - channel->alias[REMOTE] = tal_steal(channel, alias_remote); - /* Remember that we got the lockin */ wallet_channel_save(channel->peer->ld->wallet, channel); @@ -1051,19 +1059,21 @@ static void peer_got_announcement(struct channel *channel, const u8 *msg) { secp256k1_ecdsa_signature remote_ann_node_sig; secp256k1_ecdsa_signature remote_ann_bitcoin_sig; + struct short_channel_id scid; if (!fromwire_channeld_got_announcement(msg, - &remote_ann_node_sig, - &remote_ann_bitcoin_sig)) { + &scid, + &remote_ann_node_sig, + &remote_ann_bitcoin_sig)) { channel_internal_error(channel, "bad channel_got_announcement %s", tal_hex(tmpctx, msg)); return; } - wallet_announcement_save(channel->peer->ld->wallet, channel->dbid, - &remote_ann_node_sig, - &remote_ann_bitcoin_sig); + channel_gossip_got_announcement_sigs(channel, scid, + &remote_ann_node_sig, + &remote_ann_bitcoin_sig); } static void peer_got_shutdown(struct channel *channel, const u8 *msg) @@ -1102,10 +1112,14 @@ static void peer_got_shutdown(struct channel *channel, const u8 *msg) /* Get connectd to send warning, and then allow reconnect. */ subd_send_msg(ld->connectd, - take(towire_connectd_peer_final_msg(NULL, - &channel->peer->id, - channel->peer->connectd_counter, - warning))); + take(towire_connectd_peer_send_msg(NULL, + &channel->peer->id, + channel->peer->connectd_counter, + warning))); + subd_send_msg(ld->connectd, + take(towire_connectd_discard_peer(NULL, + &channel->peer->id, + channel->peer->connectd_counter))); channel_fail_transient(channel, true, "Bad shutdown scriptpubkey %s", tal_hex(tmpctx, scriptpubkey)); return; @@ -1222,23 +1236,6 @@ static void handle_error_channel(struct channel *channel, forget(channel); } -static void handle_local_private_channel(struct channel *channel, const u8 *msg) -{ - struct amount_sat capacity; - u8 *features; - - if (!fromwire_channeld_local_private_channel(msg, msg, &capacity, - &features)) { - channel_internal_error(channel, - "bad channeld_local_private_channel %s", - tal_hex(channel, msg)); - return; - } - - tell_gossipd_local_private_channel(channel->peer->ld, channel, - capacity, features); -} - static void forget_channel(struct channel *channel, const char *why) { channel->error = towire_errorfmt(channel, &channel->cid, "%s", why); @@ -1291,21 +1288,6 @@ static void handle_channel_upgrade(struct channel *channel, wallet_channel_save(channel->peer->ld->wallet, channel); } -static void handle_local_channel_update(struct channel *channel, - const u8 *msg) -{ - bool enable; - - if (!fromwire_channeld_local_channel_update(msg, &enable)) { - channel_internal_error(channel, - "bad channeld_local_channel_update %s", - tal_hex(channel, msg)); - return; - } - - tell_gossipd_local_channel_update(channel->peer->ld, channel, enable); -} - static void handle_local_anchors(struct channel *channel, const u8 *msg) { u64 remote_commitnum; @@ -1360,6 +1342,9 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds) case WIRE_CHANNELD_GOT_SHUTDOWN: peer_got_shutdown(sd->channel, msg); break; + case WIRE_CHANNELD_REESTABLISHED: + channel_gossip_channel_reestablished(sd->channel); + break; case WIRE_CHANNELD_SHUTDOWN_COMPLETE: /* We expect 1 fd. */ if (!fds) @@ -1372,15 +1357,6 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds) case WIRE_CHANNELD_SEND_ERROR_REPLY: handle_error_channel(sd->channel, msg); break; - case WIRE_CHANNELD_LOCAL_CHANNEL_UPDATE: - handle_local_channel_update(sd->channel, msg); - break; - case WIRE_CHANNELD_LOCAL_CHANNEL_ANNOUNCEMENT: - tell_gossipd_local_channel_announce(sd->ld, sd->channel, msg); - break; - case WIRE_CHANNELD_LOCAL_PRIVATE_CHANNEL: - handle_local_private_channel(sd->channel, msg); - break; case WIRE_CHANNELD_SPLICE_CONFIRMED_INIT: handle_splice_confirmed_init(sd->ld, sd->channel, msg); break; @@ -1462,9 +1438,7 @@ bool peer_start_channeld(struct channel *channel, u64 num_revocations; struct lightningd *ld = channel->peer->ld; const struct config *cfg = &ld->config; - bool reached_announce_depth; struct secret last_remote_per_commit_secret; - secp256k1_ecdsa_signature *remote_ann_node_sig, *remote_ann_bitcoin_sig; struct penalty_base *pbases; u32 min_feerate, max_feerate, curr_blockheight; struct channel_inflight *inflight; @@ -1507,16 +1481,9 @@ bool peer_start_channeld(struct channel *channel, if (channel->scid) { scid = *channel->scid; - reached_announce_depth - = is_scid_depth_announceable(&scid, - get_block_height(ld->topology)); - log_debug(channel->log, "Already have funding locked in%s", - reached_announce_depth - ? " (and ready to announce)" : ""); + log_debug(channel->log, "Already have funding locked in"); } else { - log_debug(channel->log, "Waiting for funding confirmations"); memset(&scid, 0, sizeof(scid)); - reached_announce_depth = false; } num_revocations = revocations_received(&channel->their_shachain.chain); @@ -1545,16 +1512,6 @@ bool peer_start_channeld(struct channel *channel, if (channel->ignore_fee_limits || ld->config.ignore_fee_limits) log_unusual(channel->log, "Ignoring fee limits!"); - if (!wallet_remote_ann_sigs_load(tmpctx, channel->peer->ld->wallet, - channel->dbid, - &remote_ann_node_sig, - &remote_ann_bitcoin_sig)) { - channel_internal_error(channel, - "Could not load remote announcement" - " signatures"); - return false; - } - pbases = wallet_penalty_base_load_for_channel( tmpctx, channel->peer->ld->wallet, channel->dbid); @@ -1655,8 +1612,6 @@ bool peer_start_channeld(struct channel *channel, channel->our_msat, &channel->local_basepoints, &channel->local_funding_pubkey, - &ld->id, - &channel->peer->id, cfg->commit_time_ms, channel->last_was_revoke, channel->last_sent_commit, @@ -1678,14 +1633,10 @@ bool peer_start_channeld(struct channel *channel, channel->shutdown_scriptpubkey[LOCAL], channel->channel_flags, fwd_msg, - reached_announce_depth, &last_remote_per_commit_secret, channel->peer->their_features, channel->remote_upfront_shutdown_script, - remote_ann_node_sig, - remote_ann_bitcoin_sig, channel->type, - ld->dev_fast_gossip, ld->dev_disable_commit == -1 ? NULL : (u32 *)&ld->dev_disable_commit, @@ -1693,7 +1644,8 @@ bool peer_start_channeld(struct channel *channel, reestablish_only, ld->experimental_upgrade_protocol, cast_const2(const struct inflight **, - inflights)); + inflights), + channel->alias[LOCAL]); /* We don't expect a response: we are triggered by funding_depth_cb. */ subd_send_msg(channel->owner, take(initmsg)); @@ -1706,13 +1658,17 @@ bool peer_start_channeld(struct channel *channel, get_block_height(ld->topology)); } + /* "Reestablished" if we've just opened. */ + if (!reconnected) + channel_gossip_channel_reestablished(channel); + /* FIXME: DTODO: Use a pointer to a txid instead of zero'ing one out. */ memset(&txid, 0, sizeof(txid)); /* Artificial confirmation event for zeroconf */ subd_send_msg(channel->owner, take(towire_channeld_funding_depth( - NULL, channel->scid, channel->alias[LOCAL], 0, false, + NULL, channel->scid, 0, false, &txid))); return true; } @@ -1735,7 +1691,7 @@ void channeld_tell_depth(struct channel *channel, subd_send_msg(channel->owner, take(towire_channeld_funding_depth( - NULL, channel->scid, channel->alias[LOCAL], depth, + NULL, channel->scid, depth, false, txid))); } @@ -1963,12 +1919,6 @@ struct command_result *cancel_channel_before_broadcast(struct command *cmd, return command_still_pending(cmd); } -void channel_replace_update(struct channel *channel, u8 *update TAKES) -{ - tal_free(channel->channel_update); - channel->channel_update = tal_dup_talarr(channel, u8, update); -} - static struct command_result *param_channel_for_splice(struct command *cmd, const char *name, const char *buffer, diff --git a/lightningd/channel_control.h b/lightningd/channel_control.h index d8c52bdb1141..638fac464f1f 100644 --- a/lightningd/channel_control.h +++ b/lightningd/channel_control.h @@ -33,7 +33,8 @@ struct command_result *cancel_channel_before_broadcast(struct command *cmd, /* Update the channel info on channel_ready */ bool channel_on_channel_ready(struct channel *channel, - struct pubkey *next_per_commitment_point); + const struct pubkey *next_per_commitment_point, + const struct short_channel_id *remote_alias); /* Record channel open (coin movement notifications) */ void channel_record_open(struct channel *channel, u32 blockheight, bool record_push); @@ -41,9 +42,6 @@ void channel_record_open(struct channel *channel, u32 blockheight, bool record_p /* A channel has unrecoverably fallen behind */ void channel_fallen_behind(struct channel *channel, const u8 *msg); -/* Fresh channel_update for this channel. */ -void channel_replace_update(struct channel *channel, u8 *update TAKES); - /* Tell channel about new feerates (owner must be channeld!) */ void channel_update_feerates(struct lightningd *ld, const struct channel *channel); diff --git a/lightningd/channel_gossip.c b/lightningd/channel_gossip.c new file mode 100644 index 000000000000..97a9d81d73e8 --- /dev/null +++ b/lightningd/channel_gossip.c @@ -0,0 +1,1093 @@ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum channel_gossip_state { + /* Not a public channel */ + CGOSSIP_PRIVATE, + /* We can't yet send (non-forwardable) channel_update. */ + CGOSSIP_NOT_USABLE, + /* Not yet in at announcable depth. */ + CGOSSIP_NOT_DEEP_ENOUGH, + /* We want the peer's announcement_signatures. */ + CGOSSIP_NEED_PEER_SIGS, + /* We have received sigs, and announced. */ + CGOSSIP_ANNOUNCED, +}; + +struct remote_announce_sigs { + struct short_channel_id scid; + secp256k1_ecdsa_signature node_sig; + secp256k1_ecdsa_signature bitcoin_sig; +}; + +struct channel_gossip { + enum channel_gossip_state state; + + /* Cached update info */ + const u8 *cupdate; + + /* Remote channel_announcement sigs we've received (but not + * necessarily committed!) */ + struct remote_announce_sigs *remote_sigs; + + /* Timer to refresh public channels every 13 days */ + struct oneshot *refresh_timer; + + /* Details of latest channel_update sent by peer */ + const struct peer_update *peer_update; +}; + +static bool starting_up = true, gossipd_init_done = false; + +/* We send non-forwardable channel updates if we can. */ +static bool can_send_channel_update(const struct channel *channel) +{ + /* Can't send if we can't talk about it. */ + if (!channel->scid && !channel->alias[REMOTE]) + return false; + if (channel_state_pre_open(channel->state)) + return false; + return true; +} + +/* We send start the channel announcement signatures if we can. + * Caller must check it's not CGOSSIP_PRIVATE, but this is used + * to set up state so we cannot assert here! + */ +static bool channel_announceable(const struct channel *channel, + u32 block_height) +{ + if (!channel->scid) + return false; + return is_scid_depth_announceable(channel->scid, block_height); +} + +static void check_channel_gossip(const struct channel *channel) +{ + struct channel_gossip *cg = channel->channel_gossip; + + /* Note: we can't assert is_scid_depth_announceable, for two reasons: + * 1. on restart and rescan, block numbers can go backwards.' + * 2. We don't get notified via channel_gossip_notify_new_block until + * there are no new blocks to add, not on every block. + */ + switch (cg->state) { + case CGOSSIP_PRIVATE: + assert(!(channel->channel_flags & CHANNEL_FLAGS_ANNOUNCE_CHANNEL)); + assert(!cg->remote_sigs); + assert(!cg->refresh_timer); + return; + + case CGOSSIP_NOT_USABLE: + assert(channel->channel_flags & CHANNEL_FLAGS_ANNOUNCE_CHANNEL); + assert(!can_send_channel_update(channel)); + assert(!cg->refresh_timer); + return; + case CGOSSIP_NOT_DEEP_ENOUGH: + assert(channel->channel_flags & CHANNEL_FLAGS_ANNOUNCE_CHANNEL); + assert(can_send_channel_update(channel)); + assert(!cg->refresh_timer); + return; + case CGOSSIP_NEED_PEER_SIGS: + assert(can_send_channel_update(channel)); + assert(channel->scid); + /* If we have sigs, they don't match */ + if (cg->remote_sigs) + assert(!channel->scid || !short_channel_id_eq(&cg->remote_sigs->scid, channel->scid)); + assert(!cg->refresh_timer); + return; + case CGOSSIP_ANNOUNCED: + assert(can_send_channel_update(channel)); + assert(channel->scid); + assert(cg->remote_sigs); + return; + } + fatal("Bad channel_gossip_state %u", cg->state); +} + +/* Recursion */ +static void cupdate_timer_refresh(struct channel *channel); + +static void set_public_cupdate(struct channel *channel, + const u8 *cupdate TAKES) +{ + struct lightningd *ld = channel->peer->ld; + struct channel_gossip *cg = channel->channel_gossip; + u32 timestamp; + bool enabled; + struct timeabs now, due; + + if (!channel_update_details(cupdate, ×tamp, &enabled)) { + log_broken(channel->log, "Invalid channel_update %s: ignoring", + tal_hex(tmpctx, cupdate)); + if (taken(cupdate)) + tal_free(cupdate); + return; + } + + tal_free(cg->cupdate); + cg->cupdate = tal_dup_talarr(cg, u8, cupdate); + + cg->refresh_timer = tal_free(cg->refresh_timer); + + /* If enabled, we refresh, based on old timestamp */ + if (!enabled) + return; + + due.ts.tv_sec = timestamp; + due.ts.tv_nsec = 0; + due = timeabs_add(due, + time_from_sec(GOSSIP_PRUNE_INTERVAL(ld->dev_fast_gossip_prune) + - GOSSIP_BEFORE_DEADLINE(ld->dev_fast_gossip_prune))); + + /* In case it's passed, timer should be zero */ + now = time_now(); + if (time_after(now, due)) + due = now; + + cg->refresh_timer = new_reltimer(ld->timers, cg, + time_between(due, now), + cupdate_timer_refresh, + channel); +} + +static void msg_to_peer(const struct channel *channel, const u8 *msg TAKES) +{ + struct peer *peer = channel->peer; + struct lightningd *ld = peer->ld; + + /* Shutting down, or peer not connected? */ + if (ld->connectd && peer->connected == PEER_CONNECTED) { + subd_send_msg(ld->connectd, + take(towire_connectd_peer_send_msg(NULL, + &peer->id, + peer->connectd_counter, + msg))); + } + + if (taken(msg)) + tal_free(msg); +} + +static enum channel_gossip_state init_public_state(struct channel *channel, + const struct remote_announce_sigs *remote_sigs) +{ + struct lightningd *ld = channel->peer->ld; + + if (!can_send_channel_update(channel)) + return CGOSSIP_NOT_USABLE; + + /* Note: depth when we startup is not actually reliable, since + * we step one block back. We'll fix this up when gossipd + * tells us it's announced, or, when we add the block. */ + if (!channel_announceable(channel, get_block_height(ld->topology))) + return CGOSSIP_NOT_DEEP_ENOUGH; + + if (!remote_sigs) { + return CGOSSIP_NEED_PEER_SIGS; + } + + return CGOSSIP_ANNOUNCED; +} + +static u8 *sign_update(const tal_t *ctx, + struct lightningd *ld, + const u8 *unsigned_cupdate) +{ + const u8 *msg; + u8 *signed_update; + + /* Sign it please! */ + msg = hsm_sync_req(tmpctx, ld, + take(towire_hsmd_cupdate_sig_req(NULL, unsigned_cupdate))); + + if (!fromwire_hsmd_cupdate_sig_reply(ctx, msg, &signed_update)) + fatal("Reading cupdate_sig_reply: %s", tal_hex(tmpctx, msg)); + return signed_update; +} + +/* Try to send a channel_update direct to peer, unless redundant */ +static void send_private_cupdate(struct channel *channel, bool even_if_redundant) +{ + struct channel_gossip *cg = channel->channel_gossip; + const u8 *cupdate; + const struct short_channel_id *scid; + + /* BOLT #7: + * + * - MAY create a `channel_update` to communicate the channel + * parameters to the channel peer, even though the channel has not + * yet been announced (i.e. the `announce_channel` bit was not set). + * - MUST set the `short_channel_id` to either an `alias` it has + * received from the peer, or the real channel `short_channel_id`. + * - MUST set `dont_forward` to 1 in `message_flags` + */ + /* We prefer their alias, if possible: they might not have seen the block which + * mined the funding tx yet, so the scid would be meaningless to them. */ + if (channel->alias[REMOTE]) + scid = channel->alias[REMOTE]; + else + scid = channel->scid; + + /* Only useful channels: not if closing */ + if (!channel_state_can_add_htlc(channel->state)) + return; + + /* We always set "enabled" on unannounced channels, since if peer + * receives it, that's what it means */ + cupdate = unsigned_channel_update(tmpctx, channel, scid, + NULL, false, true); + + /* Suppress redundant ones (except on reconnect, in case it's + * lost) */ + if (cg->cupdate) { + if (!even_if_redundant + && channel_update_same(cg->cupdate, cupdate)) { + return; + } + tal_free(cg->cupdate); + } + + cg->cupdate = sign_update(cg, channel->peer->ld, cupdate); + msg_to_peer(channel, cg->cupdate); +} + +static void broadcast_public_cupdate_addgossip_reply(struct subd *gossip UNUSED, + const u8 *reply, + const int *fds UNUSED, + struct channel *channel) +{ + char *err; + + if (!fromwire_gossipd_addgossip_reply(reply, reply, &err)) + fatal("Reading broadcast_public_cupdate_addgossip_reply: %s", + tal_hex(tmpctx, reply)); + + if (strlen(err)) + log_broken(channel->log, "gossipd rejected our channel update: %s", err); +} + +/* Send gossipd a channel_update, if not redundant. */ +static void broadcast_public_cupdate(struct channel *channel, + bool ok_if_disconnected) +{ + struct lightningd *ld = channel->peer->ld; + struct channel_gossip *cg = channel->channel_gossip; + const u8 *cupdate; + u32 old_timestamp; + bool enable, have_old; + + /* If we have no previous channel_update, this fails */ + have_old = channel_update_details(cg->cupdate, + &old_timestamp, &enable); + + if (!channel_state_can_add_htlc(channel->state)) { + /* If it's (no longer) usable, it's a simply courtesy + * to disable */ + enable = false; + } else if (channel->owner) { + /* If it's live, it's enabled */ + enable = true; + } else if (starting_up) { + /* If we are starting up, don't change it! */ + if (!have_old) + /* Assume the best if we don't have an updated */ + enable = true; + } else { + enable = ok_if_disconnected; + } + + cupdate = unsigned_channel_update(tmpctx, channel, channel->scid, + have_old ? &old_timestamp : NULL, + true, + enable); + + /* Suppress redundant ones */ + if (cg->cupdate && channel_update_same(cg->cupdate, cupdate)) + return; + + set_public_cupdate(channel, + take(sign_update(NULL, channel->peer->ld, cupdate))); + + subd_req(ld->gossip, ld->gossip, + take(towire_gossipd_addgossip(NULL, cg->cupdate)), + -1, 0, broadcast_public_cupdate_addgossip_reply, channel); +} + +static void cupdate_timer_refresh(struct channel *channel) +{ + struct channel_gossip *cg = channel->channel_gossip; + + /* Don't try to free this again if set_public_cupdate called later */ + cg->refresh_timer = NULL; + + log_debug(channel->log, "Sending keepalive channel_update for %s", + short_channel_id_to_str(tmpctx, channel->scid)); + + /* Free old cupdate to force a new one to be generated */ + cg->cupdate = tal_free(cg->cupdate); + broadcast_public_cupdate(channel, true); +} + +static void stash_remote_announce_sigs(struct channel *channel, + struct short_channel_id scid, + const secp256k1_ecdsa_signature *node_sig, + const secp256k1_ecdsa_signature *bitcoin_sig) +{ + struct channel_gossip *cg = channel->channel_gossip; + const char *err; + + /* BOLT #7: + * - if the `node_signature` OR the `bitcoin_signature` is NOT correct: + * - MAY send a `warning` and close the connection, or send an + * `error` and fail the channel. + */ + err = check_announce_sigs(channel, scid, node_sig, bitcoin_sig); + if (err) { + channel_fail_transient(channel, true, + "Bad gossip announcement_signatures for scid %s: %s", + short_channel_id_to_str(tmpctx, &scid), + err); + return; + } + + tal_free(cg->remote_sigs); + cg->remote_sigs = tal(cg, struct remote_announce_sigs); + cg->remote_sigs->scid = scid; + cg->remote_sigs->node_sig = *node_sig; + cg->remote_sigs->bitcoin_sig = *bitcoin_sig; + log_debug(channel->log, + "channel_gossip: received announcement sigs for %s (we have %s)", + short_channel_id_to_str(tmpctx, &scid), + channel->scid ? short_channel_id_to_str(tmpctx, channel->scid) : "none"); +} + +static bool apply_remote_sigs(struct channel *channel) +{ + struct channel_gossip *cg = channel->channel_gossip; + + if (!cg->remote_sigs) + return false; + + if (!short_channel_id_eq(&cg->remote_sigs->scid, channel->scid)) { + log_debug(channel->log, "We have remote sigs, but wrong scid!"); + return false; + } + + wallet_announcement_save(channel->peer->ld->wallet, + channel->dbid, + &cg->remote_sigs->node_sig, + &cg->remote_sigs->bitcoin_sig); + return true; +} + +static void send_channel_announce_sigs(struct channel *channel) +{ + /* First 2 + 256 byte are the signatures and msg type, skip them */ + const size_t offset = 258; + struct lightningd *ld = channel->peer->ld; + struct sha256_double hash; + secp256k1_ecdsa_signature local_node_sig, local_bitcoin_sig; + struct pubkey mykey; + const u8 *ca, *msg; + + /* If it's already closing, don't bother. */ + if (!channel_state_can_add_htlc(channel->state)) + return; + + /* Wait until we've exchanged reestablish messages */ + if (!channel->reestablished) { + log_debug(channel->log, "channel_gossip: not sending channel_announcement_sigs until reestablished"); + return; + } + + ca = create_channel_announcement(tmpctx, channel, *channel->scid, + NULL, NULL, NULL, NULL); + + msg = hsm_sync_req(tmpctx, ld, + take(towire_hsmd_sign_any_cannouncement_req(NULL, + ca, + &channel->peer->id, + channel->dbid))); + if (!fromwire_hsmd_sign_any_cannouncement_reply(msg, &local_node_sig, &local_bitcoin_sig)) + fatal("Reading hsmd_sign_any_cannouncement_reply: %s", tal_hex(tmpctx, msg)); + + /* Double-check that HSM gave valid signatures. */ + sha256_double(&hash, ca + offset, tal_count(ca) - offset); + if (!pubkey_from_node_id(&mykey, &ld->id)) + fatal("Could not convert own public key"); + + if (!check_signed_hash(&hash, &local_node_sig, &mykey)) { + channel_internal_error(channel, + "HSM returned an invalid node signature"); + return; + } + + if (!check_signed_hash(&hash, &local_bitcoin_sig, &channel->local_funding_pubkey)) { + channel_internal_error(channel, + "HSM returned an invalid bitcoin signature"); + return; + } + + msg = towire_announcement_signatures(NULL, + &channel->cid, channel->scid, + &local_node_sig, &local_bitcoin_sig); + msg_to_peer(channel, take(msg)); +} + +static void send_channel_announce_addgossip_reply(struct subd *gossip UNUSED, + const u8 *reply, + const int *fds UNUSED, + struct channel *channel) +{ + char *err; + + if (!fromwire_gossipd_addgossip_reply(reply, reply, &err)) + fatal("Reading send_channel_announce_addgossip_reply: %s", + tal_hex(tmpctx, reply)); + + if (strlen(err)) + log_broken(channel->log, "gossipd rejected our channel announcement: %s", err); +} + +static void send_channel_announcement(struct channel *channel) +{ + secp256k1_ecdsa_signature local_node_sig, local_bitcoin_sig; + struct lightningd *ld = channel->peer->ld; + const u8 *ca, *msg; + struct channel_gossip *cg = channel->channel_gossip; + + ca = create_channel_announcement(tmpctx, channel, *channel->scid, + NULL, NULL, + &cg->remote_sigs->node_sig, + &cg->remote_sigs->bitcoin_sig); + + msg = hsm_sync_req(tmpctx, ld, + take(towire_hsmd_sign_any_cannouncement_req(NULL, ca, + &channel->peer->id, + channel->dbid))); + if (!fromwire_hsmd_sign_any_cannouncement_reply(msg, + &local_node_sig, + &local_bitcoin_sig)) + fatal("Reading hsmd_sign_any_cannouncement_reply: %s", tal_hex(tmpctx, msg)); + + /* Don't crash if shutting down */ + if (!ld->gossip) + return; + + ca = create_channel_announcement(tmpctx, channel, *channel->scid, + &local_node_sig, + &local_bitcoin_sig, + &cg->remote_sigs->node_sig, + &cg->remote_sigs->bitcoin_sig); + + subd_req(ld->gossip, ld->gossip, + take(towire_gossipd_addgossip(NULL, ca)), + -1, 0, send_channel_announce_addgossip_reply, channel); + /* We can also send our first public channel_update now */ + broadcast_public_cupdate(channel, true); + /* And maybe our first node_announcement */ + channel_gossip_node_announce(ld); +} + +static void set_gossip_state(struct channel *channel, + enum channel_gossip_state state) +{ + struct channel_gossip *cg = channel->channel_gossip; + + cg->state = state; + + switch (cg->state) { + case CGOSSIP_PRIVATE: + abort(); + case CGOSSIP_NOT_USABLE: + return; + case CGOSSIP_NOT_DEEP_ENOUGH: + /* But it exists, so try sending private channel_update */ + send_private_cupdate(channel, false); + return; + case CGOSSIP_NEED_PEER_SIGS: + send_channel_announce_sigs(channel); + /* We may already have remote signatures */ + if (!apply_remote_sigs(channel)) + return; + cg->state = CGOSSIP_ANNOUNCED; + /* fall thru */ + case CGOSSIP_ANNOUNCED: + /* Any previous update was private, so clear. */ + cg->cupdate = tal_free(cg->cupdate); + send_channel_announcement(channel); + return; + } + fatal("Bad channel_gossip_state %u", cg->state); +} + +/* Initialize channel->channel_gossip state */ +void channel_gossip_init(struct channel *channel, + const struct peer_update *remote_update) +{ + struct lightningd *ld = channel->peer->ld; + struct channel_gossip *cg; + bool public = (channel->channel_flags & CHANNEL_FLAGS_ANNOUNCE_CHANNEL); + + cg = channel->channel_gossip = tal(channel, struct channel_gossip); + cg->cupdate = NULL; + cg->refresh_timer = NULL; + cg->peer_update = tal_dup_or_null(channel, struct peer_update, remote_update); + cg->remote_sigs = NULL; + + /* If we have an scid, we might have announcement signatures + * saved in the db already. */ + if (channel->scid && public) { + cg->remote_sigs = tal(cg, struct remote_announce_sigs); + cg->remote_sigs->scid = *channel->scid; + if (!wallet_remote_ann_sigs_load(ld->wallet, + channel, + &cg->remote_sigs->node_sig, + &cg->remote_sigs->bitcoin_sig)) { + cg->remote_sigs = tal_free(cg->remote_sigs); + } + } + + if (public) + cg->state = init_public_state(channel, cg->remote_sigs); + else + cg->state = CGOSSIP_PRIVATE; + + check_channel_gossip(channel); +} + +/* Something about channel changed: update if required */ +void channel_gossip_update(struct channel *channel) +{ + struct lightningd *ld = channel->peer->ld; + struct channel_gossip *cg = channel->channel_gossip; + + /* Ignore unsaved channels */ + if (!cg) + return; + + switch (cg->state) { + case CGOSSIP_NOT_USABLE: + /* Change might make it usable */ + if (!can_send_channel_update(channel)) { + check_channel_gossip(channel); + return; + } + set_gossip_state(channel, CGOSSIP_NOT_DEEP_ENOUGH); + /* fall thru */ + case CGOSSIP_NOT_DEEP_ENOUGH: + /* Now we can send at non-forwardable update */ + send_private_cupdate(channel, false); + /* Might have gotten straight from not-usable to announceable + * if we have a flurry of blocks, or minconf >= 6. */ + if (!channel_announceable(channel, get_block_height(ld->topology))) { + check_channel_gossip(channel); + return; + } + set_gossip_state(channel, CGOSSIP_NEED_PEER_SIGS); + /* Could have actually already had sigs! */ + if (cg->state == CGOSSIP_ANNOUNCED) + goto announced; + /* fall thru */ + case CGOSSIP_PRIVATE: + case CGOSSIP_NEED_PEER_SIGS: + send_private_cupdate(channel, false); + check_channel_gossip(channel); + return; + case CGOSSIP_ANNOUNCED: + announced: + /* We don't penalize disconnected clients normally: we only + * do that if we actually try to send an htlc through */ + broadcast_public_cupdate(channel, true); + check_channel_gossip(channel); + return; + } + fatal("Bad channel_gossip_state %u", channel->channel_gossip->state); +} + +void channel_gossip_got_announcement_sigs(struct channel *channel, + struct short_channel_id scid, + const secp256k1_ecdsa_signature *node_sig, + const secp256k1_ecdsa_signature *bitcoin_sig) +{ + /* Ignore unsaved channels */ + if (!channel->channel_gossip) { + log_broken(channel->log, "They sent an announcement_signatures message for a unsaved channel? Ignoring."); + return; + } + + switch (channel->channel_gossip->state) { + case CGOSSIP_PRIVATE: + log_unusual(channel->log, "They sent an announcement_signatures message for a private channel? Ignoring."); + u8 *warning = towire_warningfmt(NULL, + &channel->cid, + "You sent announcement_signatures for private channel"); + msg_to_peer(channel, take(warning)); + return; + case CGOSSIP_NOT_USABLE: + case CGOSSIP_NOT_DEEP_ENOUGH: + /* They're early? */ + stash_remote_announce_sigs(channel, + scid, node_sig, bitcoin_sig); + check_channel_gossip(channel); + return; + case CGOSSIP_NEED_PEER_SIGS: + stash_remote_announce_sigs(channel, + scid, node_sig, bitcoin_sig); + if (apply_remote_sigs(channel)) + set_gossip_state(channel, CGOSSIP_ANNOUNCED); + check_channel_gossip(channel); + return; + case CGOSSIP_ANNOUNCED: + /* BOLT #7: + * - upon reconnection (once the above timing requirements + * have been met): + * - MUST respond to the first `announcement_signatures` + * message with its own `announcement_signatures` message. + */ + send_channel_announce_sigs(channel); + check_channel_gossip(channel); + return; + } + fatal("Bad channel_gossip_state %u", channel->channel_gossip->state); +} + +/* Short channel id changed (splice, or reorg). */ +void channel_gossip_scid_changed(struct channel *channel) +{ + struct lightningd *ld = channel->peer->ld; + struct channel_gossip *cg = channel->channel_gossip; + + /* Ignore unsaved channels */ + if (!cg) + return; + + /* Clear any cached update, we'll need a new one! */ + cg->cupdate = tal_free(cg->cupdate); + + /* Any announcement signatures we received for old scid are no longer + * valid. */ + wallet_remote_ann_sigs_clear(ld->wallet, channel); + + switch (cg->state) { + case CGOSSIP_PRIVATE: + /* Still private, just send new channel_update */ + send_private_cupdate(channel, false); + check_channel_gossip(channel); + return; + case CGOSSIP_NOT_USABLE: + /* Shouldn't happen. */ + return; + case CGOSSIP_NOT_DEEP_ENOUGH: + case CGOSSIP_NEED_PEER_SIGS: + case CGOSSIP_ANNOUNCED: + log_debug(channel->log, "channel_gossip: scid now %s", + short_channel_id_to_str(tmpctx, channel->scid)); + /* Start again. */ + /* Maybe remote announcement signatures now apply? If not, + * free them */ + if (cg->remote_sigs + && !short_channel_id_eq(&cg->remote_sigs->scid, + channel->scid)) { + cg->remote_sigs = tal_free(cg->remote_sigs); + } + + /* Stop refresh timer, we're not announcing the old one. */ + cg->refresh_timer = tal_free(cg->refresh_timer); + + set_gossip_state(channel, + init_public_state(channel, cg->remote_sigs)); + send_channel_announce_sigs(channel); + check_channel_gossip(channel); + return; + } + fatal("Bad channel_gossip_state %u", cg->state); +} + +/* Block height changed */ +static void new_blockheight(struct lightningd *ld, + struct channel *channel, + u32 block_height) +{ + switch (channel->channel_gossip->state) { + case CGOSSIP_PRIVATE: + case CGOSSIP_NEED_PEER_SIGS: + case CGOSSIP_ANNOUNCED: + case CGOSSIP_NOT_USABLE: + return; + case CGOSSIP_NOT_DEEP_ENOUGH: + if (!channel_announceable(channel, block_height)) { + check_channel_gossip(channel); + return; + } + set_gossip_state(channel, CGOSSIP_NEED_PEER_SIGS); + check_channel_gossip(channel); + return; + } + fatal("Bad channel_gossip_state %u", channel->channel_gossip->state); +} + +void channel_gossip_notify_new_block(struct lightningd *ld, + u32 block_height) +{ + struct peer *peer; + struct channel *channel; + struct peer_node_id_map_iter it; + + for (peer = peer_node_id_map_first(ld->peers, &it); + peer; + peer = peer_node_id_map_next(ld->peers, &it)) { + list_for_each(&peer->channels, channel, list) { + /* Ignore unsaved channels */ + if (!channel->channel_gossip) + continue; + + new_blockheight(ld, channel, block_height); + check_channel_gossip(channel); + } + } +} + +/* Gossipd told us about a channel update on one of our channels (on loading) */ +void channel_gossip_update_from_gossipd(struct channel *channel, + const u8 *channel_update TAKES) +{ + if (!channel->channel_gossip) { + log_broken(channel->log, + "gossipd gave channel_update for unsaved channel? update=%s", + tal_hex(tmpctx, channel_update)); + return; + } + + /* If we didn't think it was announced already, it is now! */ + switch (channel->channel_gossip->state) { + case CGOSSIP_PRIVATE: + log_broken(channel->log, + "gossipd gave channel_update for private channel? update=%s", + tal_hex(tmpctx, channel_update)); + return; + case CGOSSIP_NOT_USABLE: + case CGOSSIP_NOT_DEEP_ENOUGH: + case CGOSSIP_NEED_PEER_SIGS: + set_gossip_state(channel, CGOSSIP_ANNOUNCED); + break; + case CGOSSIP_ANNOUNCED: + break; + } + + set_public_cupdate(channel, channel_update); + check_channel_gossip(channel); +} + +static void set_not_starting_up(struct lightningd *ld) +{ + starting_up = false; + log_debug(ld->log, "channel_gossip: no longer in startup mode"); + /* Now we can create/update a node_announcement */ + channel_gossip_node_announce(ld); +} + +/* We also wait ten seconds *after* connection, for lease registration */ +void channel_gossip_startup_done(struct lightningd *ld) +{ + notleak(new_reltimer(ld->timers, ld, + time_from_sec(10), + set_not_starting_up, ld)); +} + +/* Gossipd init is done: if you expected a channel_update, be + * disappointed. */ +void channel_gossip_init_done(struct lightningd *ld) +{ + struct peer *peer; + struct channel *channel; + struct peer_node_id_map_iter it; + + gossipd_init_done = true; + for (peer = peer_node_id_map_first(ld->peers, &it); + peer; + peer = peer_node_id_map_next(ld->peers, &it)) { + list_for_each(&peer->channels, channel, list) { + /* Ignore unsaved channels */ + if (!channel->channel_gossip) + continue; + + check_channel_gossip(channel); + if (channel->channel_gossip->cupdate) + continue; + if (channel->channel_gossip->state != CGOSSIP_ANNOUNCED) + continue; + /* gossipd lost announcement: re-create */ + log_unusual(channel->log, + "gossipd lost track of announced channel: re-announcing!"); + check_channel_gossip(channel); + send_channel_announcement(channel); + } + } +} + +static void channel_reestablished_stable(struct channel *channel) +{ + channel->stable_conn_timer = NULL; + channel->last_stable_connection = time_now().ts.tv_sec; + wallet_channel_save(channel->peer->ld->wallet, channel); +} + +/* Peer has connected and successfully reestablished channel. */ +void channel_gossip_channel_reestablished(struct channel *channel) +{ + channel->reestablished = true; + tal_free(channel->stable_conn_timer); + channel->stable_conn_timer = new_reltimer(channel->peer->ld->timers, + channel, time_from_sec(60), + channel_reestablished_stable, + channel); + + log_debug(channel->log, "channel_gossip: reestablished"); + + /* Ignore unsaved channels */ + if (!channel->channel_gossip) + return; + + switch (channel->channel_gossip->state) { + case CGOSSIP_NOT_USABLE: + return; + case CGOSSIP_PRIVATE: + case CGOSSIP_NOT_DEEP_ENOUGH: + send_private_cupdate(channel, true); + check_channel_gossip(channel); + return; + case CGOSSIP_NEED_PEER_SIGS: + /* BOLT #7: + * - upon reconnection (once the above timing + * requirements have been met): + * ... + * - if it has NOT received an + * `announcement_signatures` message: + * - SHOULD retransmit the + * `announcement_signatures` message. + */ + send_private_cupdate(channel, true); + send_channel_announce_sigs(channel); + check_channel_gossip(channel); + return; + case CGOSSIP_ANNOUNCED: + check_channel_gossip(channel); + return; + } + fatal("Bad channel_gossip_state %u", channel->channel_gossip->state); +} + +void channel_gossip_channel_disconnect(struct channel *channel) +{ + channel->stable_conn_timer = tal_free(channel->stable_conn_timer); + channel->reestablished = false; +} + +/* We *could* send channel_updates for private channels, or + * unannounced. We do not */ +const u8 *channel_gossip_update_for_error(const tal_t *ctx, + struct channel *channel) +{ + /* We cannot ask this about unsaved channels. */ + struct channel_gossip *cg = channel->channel_gossip; + + switch (cg->state) { + case CGOSSIP_PRIVATE: + case CGOSSIP_NOT_USABLE: + case CGOSSIP_NOT_DEEP_ENOUGH: + case CGOSSIP_NEED_PEER_SIGS: + return NULL; + case CGOSSIP_ANNOUNCED: + broadcast_public_cupdate(channel, false); + check_channel_gossip(channel); + return cg->cupdate; + } + fatal("Bad channel_gossip_state %u", cg->state); +} + +/* BOLT #7: + * - MUST set the `short_channel_id` to either an `alias` it has + * received from the peer, or the real channel `short_channel_id`. + */ +/* But we used to get this wrong! So this is the only place where we + * look up by *remote* id. It's not unique, but it is unique for a + * specific peer. */ +static struct channel *lookup_by_peer_remote_alias(struct lightningd *ld, + const struct node_id *source, + struct short_channel_id scid) +{ + const struct peer *p; + struct channel *chan; + + if (!source) + return NULL; + + p = peer_by_id(ld, source); + if (!p) + return NULL; + + list_for_each(&p->channels, chan, list) { + if (chan->alias[REMOTE] + && short_channel_id_eq(&scid, chan->alias[REMOTE])) { + return chan; + } + } + return NULL; +} + +/* A peer sent gossipd an update_channel message for one of our channels. + * Gossipd checked the signature. + */ +void channel_gossip_set_remote_update(struct lightningd *ld, + const struct peer_update *update TAKES, + const struct node_id *source) +{ + struct channel *channel; + struct channel_gossip *cg; + + channel = any_channel_by_scid(ld, &update->scid, true); + if (!channel) { + channel = lookup_by_peer_remote_alias(ld, source, update->scid); + if (channel) + log_debug(channel->log, + "Bad gossip order: peer sent update using their own alias!"); + } + if (!channel) { + log_unusual(ld->log, "Bad gossip order: could not find channel %s for peer's " + "channel update", + short_channel_id_to_str(tmpctx, &update->scid)); + return; + } + + cg = channel->channel_gossip; + + if (!cg) { + log_broken(ld->log, "Peer sent update_channel for unsaved channel"); + return; + } + + /* For public channels, it could come from anywhere. Private + * channels must come from gossipd itself (the old store + * migration!) or the correct peer. */ + if (cg->state == CGOSSIP_PRIVATE + && source + && !node_id_eq(source, &channel->peer->id)) { + log_unusual(ld->log, "Bad gossip order: %s sent us a channel update for a " + "channel owned by %s (%s)", + type_to_string(tmpctx, struct node_id, source), + type_to_string(tmpctx, struct node_id, + &channel->peer->id), + type_to_string(tmpctx, struct short_channel_id, &update->scid)); + return; + } + + log_debug(ld->log, "updating channel %s with inbound settings", + type_to_string(tmpctx, struct short_channel_id, &update->scid)); + tal_free(cg->peer_update); + cg->peer_update = tal_dup(cg, struct peer_update, update); + wallet_channel_save(ld->wallet, channel); +} + +const struct peer_update *channel_gossip_get_remote_update(const struct channel *channel) +{ + struct channel_gossip *cg = channel->channel_gossip; + + if (!cg) + return NULL; + return cg->peer_update; +} + +static bool has_announced_channels(struct lightningd *ld) +{ + struct peer *peer; + struct peer_node_id_map_iter it; + + for (peer = peer_node_id_map_first(ld->peers, &it); + peer; + peer = peer_node_id_map_next(ld->peers, &it)) { + struct channel *channel; + list_for_each(&peer->channels, channel, list) { + /* Ignore unsaved channels */ + if (!channel->channel_gossip) + continue; + if (channel->channel_gossip->state == CGOSSIP_ANNOUNCED) + return true; + } + } + return false; +} + +static void node_announce_addgossip_reply(struct subd *gossipd, + const u8 *reply, + const int *fds UNUSED, + void *unused) +{ + char *err; + + if (!fromwire_gossipd_addgossip_reply(reply, reply, &err)) + fatal("Reading node_announce_addgossip_reply: %s", + tal_hex(tmpctx, reply)); + + if (strlen(err)) + log_broken(gossipd->ld->log, + "gossipd rejected our node announcement: %s", err); +} + +void channel_gossip_node_announce(struct lightningd *ld) +{ + u8 *nannounce; + const u8 *msg; + secp256k1_ecdsa_signature sig; + + /* Everyone will ignore our node_announcement unless we have + * announced a channel. */ + if (!has_announced_channels(ld)) + return; + + /* Don't produce a node announcement until *after* gossipd has + * told us it's finished. */ + if (!gossipd_init_done) + return; + + nannounce = unsigned_node_announcement(tmpctx, ld, ld->node_announcement); + + /* Don't bother with duplicates */ + if (ld->node_announcement + && node_announcement_same(ld->node_announcement, nannounce)) + return; + + /* Ask hsmd to sign it (synchronous) */ + msg = hsm_sync_req(tmpctx, ld, + take(towire_hsmd_node_announcement_sig_req(NULL, + nannounce))); + if (!fromwire_hsmd_node_announcement_sig_reply(msg, &sig)) + fatal("Reading hsmd_node_announcement_sig_reply: %s", + tal_hex(tmpctx, msg)); + + add_node_announcement_sig(nannounce, &sig); + + /* Update our cached copy. */ + tal_free(ld->node_announcement); + ld->node_announcement = tal_steal(ld, nannounce); + + /* Tell gossipd. */ + subd_req(ld->gossip, ld->gossip, + take(towire_gossipd_addgossip(NULL, nannounce)), + -1, 0, node_announce_addgossip_reply, NULL); +} diff --git a/lightningd/channel_gossip.h b/lightningd/channel_gossip.h new file mode 100644 index 000000000000..0a81089dea14 --- /dev/null +++ b/lightningd/channel_gossip.h @@ -0,0 +1,64 @@ +#ifndef LIGHTNING_LIGHTNINGD_CHANNEL_GOSSIP_H +#define LIGHTNING_LIGHTNINGD_CHANNEL_GOSSIP_H +#include "config.h" +#include +#include + +struct channel; +struct lightningd; +struct peer; +struct peer_update; + +/* Initialize channel->channel_gossip state */ +void channel_gossip_init(struct channel *channel, + const struct peer_update *remote_update TAKES); + +/* We've attempted reconnect to all peers. */ +void channel_gossip_startup_done(struct lightningd *ld); + +/* Something about channel/blockchain changed: update if required */ +void channel_gossip_update(struct channel *channel); + +/* Short channel id changed (splice, or reorg). */ +void channel_gossip_scid_changed(struct channel *channel); + +/* Block height changed */ +void channel_gossip_notify_new_block(struct lightningd *ld, + u32 block_height); + +/* Got announcement_signatures from peer */ +void channel_gossip_got_announcement_sigs(struct channel *channel, + struct short_channel_id scid, + const secp256k1_ecdsa_signature *node_sig, + const secp256k1_ecdsa_signature *bitcoin_sig); + +/* If node_announcement has changed, send a new one. */ +void channel_gossip_node_announce(struct lightningd *ld); + +/* Gossipd told us about a channel update on one of our channels (on loading) */ +void channel_gossip_update_from_gossipd(struct channel *channel, + const u8 *channel_update TAKES); + +/* Gossipd init is done: if you expected a channel_update, be + * disappointed. */ +void channel_gossip_init_done(struct lightningd *ld); + +/* Peer has connected and successfully reestablished channel. */ +void channel_gossip_channel_reestablished(struct channel *channel); + +/* Peer has disconnected */ +void channel_gossip_channel_disconnect(struct channel *channel); + +/* Gossipd sent us this channel_update about the peer's side of the channel */ +void channel_gossip_set_remote_update(struct lightningd *ld, + const struct peer_update *update TAKES, + const struct node_id *source); + +/* Get channel_update to send in an error onion reply (can give NULL!) */ +const u8 *channel_gossip_update_for_error(const tal_t *ctx, + struct channel *channel); + +/* Get the peer's last-sent channel_update info, if any. */ +const struct peer_update *channel_gossip_get_remote_update(const struct channel *channel); + +#endif /* LIGHTNING_LIGHTNINGD_CHANNEL_GOSSIP_H */ diff --git a/lightningd/closed_channel.c b/lightningd/closed_channel.c index 67f24cad983a..11ae1133df59 100644 --- a/lightningd/closed_channel.c +++ b/lightningd/closed_channel.c @@ -76,6 +76,10 @@ static void json_add_closed_channel(struct json_stream *response, } json_add_string(response, "close_cause", channel_change_state_reason_str(channel->state_change_cause)); + if (channel->last_stable_connection != 0) { + json_add_u64(response, "last_stable_connection", + channel->last_stable_connection); + } json_object_end(response); } diff --git a/lightningd/closed_channel.h b/lightningd/closed_channel.h index 44a2269fe184..13f58d62b4fe 100644 --- a/lightningd/closed_channel.h +++ b/lightningd/closed_channel.h @@ -27,6 +27,7 @@ struct closed_channel { const struct channel_type *type; enum state_change state_change_cause; bool leased; + u64 last_stable_connection; }; #endif /* LIGHTNING_LIGHTNINGD_CLOSED_CHANNEL_H */ diff --git a/lightningd/closing_control.c b/lightningd/closing_control.c index cd2745b7e8f6..7102cfc89308 100644 --- a/lightningd/closing_control.c +++ b/lightningd/closing_control.c @@ -508,13 +508,6 @@ void peer_start_closingd(struct channel *channel, struct peer_fd *peer_fd) /* We don't expect a response: it will give us feedback on * signatures sent and received, then closing_complete. */ subd_send_msg(channel->owner, take(initmsg)); - - /* Now tell gossipd that we're closing and that neither direction should - * be used. */ - if (channel->scid) - subd_send_msg(channel->peer->ld->gossip, - take(towire_gossipd_local_channel_close( - tmpctx, channel->scid))); } static struct command_result *param_outpoint(struct command *cmd, diff --git a/lightningd/connect_control.c b/lightningd/connect_control.c index ecb685bdd375..f13f42862469 100644 --- a/lightningd/connect_control.c +++ b/lightningd/connect_control.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -565,6 +566,15 @@ void connectd_start_shutdown(struct subd *connectd) while (io_loop(NULL, NULL) != connectd); } +static void startup_connect_one_done(struct lightningd *ld) +{ + if (!ld->num_startup_connects) + return; + + if (--ld->num_startup_connects == 0) + channel_gossip_startup_done(ld); +} + static unsigned connectd_msg(struct subd *connectd, const u8 *msg, const int *fds) { enum connectd_wire t = fromwire_peektype(msg); @@ -578,7 +588,7 @@ static unsigned connectd_msg(struct subd *connectd, const u8 *msg, const int *fd case WIRE_CONNECTD_DEV_MEMLEAK: case WIRE_CONNECTD_DEV_SUPPRESS_GOSSIP: case WIRE_CONNECTD_DEV_REPORT_FDS: - case WIRE_CONNECTD_PEER_FINAL_MSG: + case WIRE_CONNECTD_PEER_SEND_MSG: case WIRE_CONNECTD_PEER_CONNECT_SUBD: case WIRE_CONNECTD_PING: case WIRE_CONNECTD_SEND_ONIONMSG: @@ -594,6 +604,7 @@ static unsigned connectd_msg(struct subd *connectd, const u8 *msg, const int *fd break; case WIRE_CONNECTD_PEER_CONNECTED: + startup_connect_one_done(connectd->ld); peer_connected(connectd->ld, msg); break; @@ -606,6 +617,7 @@ static unsigned connectd_msg(struct subd *connectd, const u8 *msg, const int *fd break; case WIRE_CONNECTD_CONNECT_FAILED: + startup_connect_one_done(connectd->ld); handle_connect_failed(connectd->ld, msg); break; diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index 3fe3fe0ede73..d89138d32ad3 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -33,7 +34,6 @@ #include #include #include -#include struct commit_rcvd { struct channel *channel; @@ -1465,12 +1465,6 @@ wallet_commit_channel(struct lightningd *ld, = p2tr_for_keyidx(channel, channel->peer->ld, channel->final_key_idx); - /* Can't have gotten their alias for this channel yet. */ - channel->alias[REMOTE] = NULL; - /* We do generate one ourselves however. */ - channel->alias[LOCAL] = tal(channel, struct short_channel_id); - randombytes_buf(channel->alias[LOCAL], sizeof(struct short_channel_id)); - channel->remote_upfront_shutdown_script = tal_steal(channel, remote_upfront_shutdown_script); @@ -1583,10 +1577,14 @@ static void handle_peer_wants_to_close(struct subd *dualopend, /* Get connectd to send warning, and kill subd. */ subd_send_msg(ld->connectd, - take(towire_connectd_peer_final_msg(NULL, - &channel->peer->id, - channel->peer->connectd_counter, - warning))); + take(towire_connectd_peer_send_msg(NULL, + &channel->peer->id, + channel->peer->connectd_counter, + warning))); + subd_send_msg(ld->connectd, + take(towire_connectd_discard_peer(NULL, + &channel->peer->id, + channel->peer->connectd_counter))); channel_fail_transient(channel, true, "Bad shutdown scriptpubkey %s", tal_hex(tmpctx, scriptpubkey)); return; @@ -1635,24 +1633,6 @@ static void handle_channel_closed(struct subd *dualopend, "Start closingd"); } -static void handle_local_private_channel(struct subd *dualopend, - const u8 *msg) -{ - struct amount_sat capacity; - u8 *features; - - if (!fromwire_dualopend_local_private_channel(msg, msg, &capacity, - &features)) { - channel_internal_error(dualopend->channel, - "bad dualopend_local_private_channel %s", - tal_hex(msg, msg)); - return; - } - - tell_gossipd_local_private_channel(dualopend->ld, dualopend->channel, - capacity, features); -} - struct channel_send { const struct wally_tx *wtx; struct channel *channel; @@ -1940,8 +1920,11 @@ static void handle_peer_locked(struct subd *dualopend, const u8 *msg) { struct pubkey remote_per_commit; struct channel *channel = dualopend->channel; + struct short_channel_id *remote_alias; - if (!fromwire_dualopend_peer_locked(msg, &remote_per_commit)) { + if (!fromwire_dualopend_peer_locked(msg, msg, + &remote_per_commit, + &remote_alias)) { channel_internal_error(channel, "Bad WIRE_DUALOPEND_PEER_LOCKED: %s", tal_hex(msg, msg)); @@ -1950,7 +1933,7 @@ static void handle_peer_locked(struct subd *dualopend, const u8 *msg) /* Updates channel with the next per-commit point etc, calls * channel_internal_error on failure */ - if (!channel_on_channel_ready(channel, &remote_per_commit)) + if (!channel_on_channel_ready(channel, &remote_per_commit, remote_alias)) return; /* Remember that we got the lock-in */ @@ -3433,6 +3416,9 @@ static void handle_commit_ready(struct subd *dualopend, /* First time (not an RBF) */ if (channel->state == DUALOPEND_OPEN_INIT) { + /* Now we know if it's public or not, we can init channel_gossip */ + assert(channel->channel_gossip == NULL); + channel_gossip_init(channel, NULL); if (!(inflight = wallet_commit_channel(ld, channel, &funding, total_funding, @@ -3643,9 +3629,6 @@ static unsigned int dual_opend_msg(struct subd *dualopend, case WIRE_DUALOPEND_FAIL_FALLEN_BEHIND: channel_fail_fallen_behind(dualopend, msg); return 0; - case WIRE_DUALOPEND_LOCAL_PRIVATE_CHANNEL: - handle_local_private_channel(dualopend, msg); - return 0; case WIRE_DUALOPEND_VALIDATE_INPUTS: handle_validate_inputs(dualopend, msg); return 0; @@ -4052,6 +4035,7 @@ bool peer_start_dualopend(struct peer *peer, &channel->local_funding_pubkey, channel->minimum_depth, peer->ld->config.require_confirmed_inputs, + channel->alias[LOCAL], peer->ld->dev_any_channel_type); subd_send_msg(channel->owner, take(msg)); return true; @@ -4165,7 +4149,8 @@ bool peer_restart_dualopend(struct peer *peer, NULL : &inflight->lease_amt, channel->type, channel->req_confirmed_ins[LOCAL], - channel->req_confirmed_ins[REMOTE]); + channel->req_confirmed_ins[REMOTE], + channel->alias[LOCAL]); subd_send_msg(channel->owner, take(msg)); return true; diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index b4083c29ad6b..db3d8867e581 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -1,18 +1,24 @@ #include "config.h" #include +#include #include #include +#include #include #include #include #include +#include #include +#include #include +#include #include #include #include #include #include +#include #include #include #include @@ -121,135 +127,40 @@ static void handle_init_cupdate(struct lightningd *ld, const u8 *msg) tal_hex(msg, msg)); } - /* In theory this could vanish before gossipd gets around to telling - * us. */ channel = any_channel_by_scid(ld, &scid, true); if (!channel) { - log_unusual(ld->log, "init_cupdate for bad scid %s", - type_to_string(tmpctx, struct short_channel_id, - &scid)); + log_broken(ld->log, "init_cupdate for unknown scid %s", + type_to_string(tmpctx, struct short_channel_id, + &scid)); return; } - /* This should only happen on initialization, *but* gossipd also - * disabled channels on startup, so that can set this first. */ - if (!channel->channel_update) - channel->channel_update = tal_steal(channel, update); + channel_gossip_update_from_gossipd(channel, take(update)); } -static void handle_local_channel_update(struct lightningd *ld, const u8 *msg) +static void handle_init_nannounce(struct lightningd *ld, const u8 *msg) { - struct short_channel_id scid; - u8 *update; - struct channel *channel; + u8 *nannounce; - if (!fromwire_gossipd_got_local_channel_update(msg, msg, - &scid, &update)) { - fatal("Gossip gave bad GOSSIP_GOT_LOCAL_CHANNEL_UPDATE %s", + if (!fromwire_gossipd_init_nannounce(ld, msg, &nannounce)) { + fatal("Gossip gave bad GOSSIPD_INIT_NANNOUNCE %s", tal_hex(msg, msg)); } - /* In theory this could vanish before gossipd gets around to telling - * us. */ - channel = any_channel_by_scid(ld, &scid, true); - if (!channel) { - log_unusual(ld->log, "Local update for bad scid %s", - type_to_string(tmpctx, struct short_channel_id, - &scid)); - return; - } - - channel_replace_update(channel, take(update)); -} - -const u8 *get_channel_update(struct channel *channel) -{ - /* Tell gossipd we're using it (if shutting down, might be NULL) */ - if (channel->channel_update && channel->peer->ld->gossip) { - subd_send_msg(channel->peer->ld->gossip, - take(towire_gossipd_used_local_channel_update - (NULL, channel->scid))); - } - return channel->channel_update; -} - -static void set_channel_remote_update(struct lightningd *ld, - struct channel *channel, - const struct node_id *source, - struct peer_update *update TAKES) -{ - struct short_channel_id *scid; - - scid = channel->scid; - if (!scid) - scid = channel->alias[LOCAL]; - - /* NULL source means it's from gossipd itself */ - if (source && !node_id_eq(source, &channel->peer->id)) { - log_unusual(ld->log, "Bad gossip order: %s sent us a channel update for a " - "channel owned by %s (%s)", - type_to_string(tmpctx, struct node_id, source), - type_to_string(tmpctx, struct node_id, - &channel->peer->id), - type_to_string(tmpctx, struct short_channel_id, scid)); - if (taken(update)) - tal_free(update); - return; - } - log_debug(ld->log, "updating channel %s with private inbound settings", - type_to_string(tmpctx, struct short_channel_id, scid)); - tal_free(channel->peer_update); - channel->peer_update = tal_dup(channel, struct peer_update, update); - if (taken(update)) - tal_free(update); - wallet_channel_save(ld->wallet, channel); -} - -/* One of the few places where we look up by *remote* id. It's not unique, - * but it is unique for a specific peer. */ -static struct channel *lookup_by_peer_remote_alias(struct lightningd *ld, - const struct node_id *source, - struct short_channel_id scid) -{ - const struct peer *p; - struct channel *chan; - - if (!source) - return NULL; - - p = peer_by_id(ld, source); - if (!p) - return NULL; - - list_for_each(&p->channels, chan, list) { - if (chan->alias[REMOTE] - && short_channel_id_eq(&scid, chan->alias[REMOTE])) - return chan; - } - return NULL; + assert(!ld->node_announcement); + ld->node_announcement = nannounce; } static void handle_peer_update_data(struct lightningd *ld, const u8 *msg) { - struct channel *channel; - struct peer_update *update; + struct peer_update update; struct node_id *source; - update = tal(tmpctx, struct peer_update); - if (!fromwire_gossipd_remote_channel_update(msg, msg, &source, update)) + if (!fromwire_gossipd_remote_channel_update(msg, msg, &source, &update)) fatal("Gossip gave bad GOSSIPD_REMOTE_CHANNEL_UPDATE %s", tal_hex(msg, msg)); - channel = any_channel_by_scid(ld, &update->scid, true); - if (!channel) - channel = lookup_by_peer_remote_alias(ld, source, update->scid); - if (!channel) { - log_unusual(ld->log, "Bad gossip order: could not find channel %s for peer's " - "channel update", - short_channel_id_to_str(tmpctx, &update->scid)); - return; - } - set_channel_remote_update(ld, channel, source, update); + channel_gossip_set_remote_update(ld, &update, source); } static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds) @@ -261,19 +172,13 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds) case WIRE_GOSSIPD_INIT: case WIRE_GOSSIPD_GET_TXOUT_REPLY: case WIRE_GOSSIPD_OUTPOINTS_SPENT: - case WIRE_GOSSIPD_NEW_LEASE_RATES: case WIRE_GOSSIPD_DEV_SET_MAX_SCIDS_ENCODE_SIZE: - case WIRE_GOSSIPD_LOCAL_CHANNEL_CLOSE: case WIRE_GOSSIPD_DEV_MEMLEAK: case WIRE_GOSSIPD_DEV_COMPACT_STORE: case WIRE_GOSSIPD_DEV_SET_TIME: case WIRE_GOSSIPD_NEW_BLOCKHEIGHT: case WIRE_GOSSIPD_ADDGOSSIP: case WIRE_GOSSIPD_GET_ADDRS: - case WIRE_GOSSIPD_USED_LOCAL_CHANNEL_UPDATE: - case WIRE_GOSSIPD_LOCAL_CHANNEL_UPDATE: - case WIRE_GOSSIPD_LOCAL_CHANNEL_ANNOUNCEMENT: - case WIRE_GOSSIPD_LOCAL_PRIVATE_CHANNEL: /* This is a reply, so never gets through to here. */ case WIRE_GOSSIPD_INIT_REPLY: case WIRE_GOSSIPD_DEV_MEMLEAK_REPLY: @@ -281,18 +186,17 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds) case WIRE_GOSSIPD_ADDGOSSIP_REPLY: case WIRE_GOSSIPD_NEW_BLOCKHEIGHT_REPLY: case WIRE_GOSSIPD_GET_ADDRS_REPLY: - case WIRE_GOSSIPD_DISCOVERED_IP: break; case WIRE_GOSSIPD_INIT_CUPDATE: handle_init_cupdate(gossip->ld, msg); break; + case WIRE_GOSSIPD_INIT_NANNOUNCE: + handle_init_nannounce(gossip->ld, msg); + break; case WIRE_GOSSIPD_GET_TXOUT: get_txout(gossip, msg); break; - case WIRE_GOSSIPD_GOT_LOCAL_CHANNEL_UPDATE: - handle_local_channel_update(gossip->ld, msg); - break; case WIRE_GOSSIPD_REMOTE_CHANNEL_UPDATE: /* Please stash in database for us! */ handle_peer_update_data(gossip->ld, msg); @@ -342,6 +246,10 @@ static void gossipd_init_done(struct subd *gossipd, const int *fds, void *unused) { + /* Any channels without channel_updates, we populate now: gossipd + * might have lost its gossip_store. */ + channel_gossip_init_done(gossipd->ld); + /* Break out of loop, so we can begin */ log_debug(gossipd->ld->log, "io_break: %s", __func__); io_break(gossipd); @@ -372,13 +280,9 @@ void gossip_init(struct lightningd *ld, int connectd_fd) chainparams, ld->our_features, &ld->id, - ld->rgb, - ld->alias, - ld->announceable, ld->dev_gossip_time ? &ld->dev_gossip_time: NULL, ld->dev_fast_gossip, - ld->dev_fast_gossip_prune, - ld->config.ip_discovery); + ld->dev_fast_gossip_prune); subd_req(ld->gossip, ld->gossip, take(msg), -1, 0, gossipd_init_done, NULL); @@ -400,91 +304,6 @@ void gossipd_notify_spends(struct lightningd *ld, scids))); } -/* Tell gossipd about latest channel_update. */ -void tell_gossipd_local_channel_update(struct lightningd *ld, - struct channel *channel, - bool enable) -{ - /* As we're shutting down, ignore */ - if (!ld->gossip) - return; - - subd_send_msg(ld->gossip, - take(towire_gossipd_local_channel_update - (NULL, - &channel->peer->id, - channel->scid ? channel->scid : channel->alias[LOCAL], - enable, - ld->config.cltv_expiry_delta, - channel->htlc_minimum_msat, - channel->feerate_base, - channel->feerate_ppm, - channel->htlc_maximum_msat, - channel->channel_flags & CHANNEL_FLAGS_ANNOUNCE_CHANNEL))); -} - -void tell_gossipd_local_channel_announce(struct lightningd *ld, - struct channel *channel, - const u8 *msg) -{ - u8 *ann; - if (!fromwire_channeld_local_channel_announcement(msg, msg, &ann)) { - channel_internal_error(channel, - "bad channeld_local_channel_announcement" - " %s", - tal_hex(channel, msg)); - return; - } - - /* As we're shutting down, ignore */ - if (!ld->gossip) - return; - - subd_send_msg(ld->gossip, - take(towire_gossipd_local_channel_announcement - (NULL, &channel->peer->id, ann))); -} - -void tell_gossipd_local_private_channel(struct lightningd *ld, - struct channel *channel, - struct amount_sat capacity, - const u8 *features) -{ - /* Which short_channel_id should we use to refer to this channel when - * creating invoices? */ - const struct short_channel_id *scid; - - /* As we're shutting down, ignore */ - if (!ld->gossip) - return; - - if (channel->scid != NULL) { - scid = channel->scid; - } else { - scid = channel->alias[REMOTE]; - } - - assert(scid != NULL); - subd_send_msg(ld->gossip, - take(towire_gossipd_local_private_channel - (NULL, &channel->peer->id, - capacity, - scid, - features))); - - /* If we have no real scid, and there are two different - * aliases, then we need to add both as single direction - * channels to the local gossip_store. */ - if ((!channel->scid && channel->alias[LOCAL]) && - !short_channel_id_eq(channel->alias[REMOTE], - channel->alias[LOCAL])) { - subd_send_msg(ld->gossip, - take(towire_gossipd_local_private_channel( - NULL, &channel->peer->id, capacity, - channel->alias[LOCAL], features))); - } -} - static struct command_result *json_setleaserates(struct command *cmd, const char *buffer, const jsmntok_t *obj UNNEEDED, @@ -527,9 +346,13 @@ static struct command_result *json_setleaserates(struct command *cmd, if (command_check_only(cmd)) return command_check_done(cmd); - /* Call gossipd, let them know we've got new rates */ - subd_send_msg(cmd->ld->gossip, - take(towire_gossipd_new_lease_rates(NULL, rates))); + /* Save them for node_announcement generation */ + cmd->ld->lease_rates = tal_free(cmd->ld->lease_rates); + if (!lease_rates_empty(rates)) + cmd->ld->lease_rates = tal_steal(cmd->ld, rates); + + /* This may generate a new node_announcement */ + channel_gossip_node_announce(cmd->ld); res = json_stream_success(cmd); json_add_amount_sat_msat(res, "lease_fee_base_msat", diff --git a/lightningd/gossip_control.h b/lightningd/gossip_control.h index 6e5b37cbbeb2..cc9827b056a2 100644 --- a/lightningd/gossip_control.h +++ b/lightningd/gossip_control.h @@ -16,16 +16,4 @@ void gossipd_notify_spends(struct lightningd *ld, void gossip_notify_new_block(struct lightningd *ld, u32 blockheight); -/* channeld tells us stuff, we tell gossipd. */ -void tell_gossipd_local_channel_update(struct lightningd *ld, - struct channel *channel, - bool enabled); -void tell_gossipd_local_channel_announce(struct lightningd *ld, - struct channel *channel, - const u8 *msg); -void tell_gossipd_local_private_channel(struct lightningd *ld, - struct channel *channel, - struct amount_sat capacity, - const u8 *features); - #endif /* LIGHTNING_LIGHTNINGD_GOSSIP_CONTROL_H */ diff --git a/lightningd/gossip_generation.c b/lightningd/gossip_generation.c new file mode 100644 index 000000000000..0cbb78468c3a --- /dev/null +++ b/lightningd/gossip_generation.c @@ -0,0 +1,452 @@ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Once we know which way nodes go, it's easy to construct */ +static u8 *create_channel_announcement_dir(const tal_t *ctx, + const u8 *features, + struct short_channel_id scid, + const secp256k1_ecdsa_signature node_signature[NUM_SIDES], + const secp256k1_ecdsa_signature bitcoin_signature[NUM_SIDES], + const struct node_id node_id[NUM_SIDES], + const struct pubkey funding_pubkey[NUM_SIDES]) +{ + enum side first, second; + + if (node_id_cmp(&node_id[LOCAL], &node_id[REMOTE]) < 0) + first = LOCAL; + else + first = REMOTE; + second = !first; + + return towire_channel_announcement(ctx, + &node_signature[first], + &node_signature[second], + &bitcoin_signature[first], + &bitcoin_signature[second], + features, + &chainparams->genesis_blockhash, + &scid, + &node_id[first], + &node_id[second], + &funding_pubkey[first], + &funding_pubkey[second]); +} + +static void copysig_or_zero(secp256k1_ecdsa_signature *dst, + const secp256k1_ecdsa_signature *src) +{ + if (!src) + memset(dst, 0, sizeof(*dst)); + else + *dst = *src; +} + +u8 *create_channel_announcement(const tal_t *ctx, + const struct channel *channel, + struct short_channel_id scid, + const secp256k1_ecdsa_signature *local_node_signature, + const secp256k1_ecdsa_signature *local_bitcoin_signature, + const secp256k1_ecdsa_signature *remote_node_signature, + const secp256k1_ecdsa_signature *remote_bitcoin_signature) +{ + secp256k1_ecdsa_signature node_signature[NUM_SIDES], bitcoin_signature[NUM_SIDES]; + struct node_id node_id[NUM_SIDES]; + struct pubkey funding_pubkey[NUM_SIDES]; + u8 *features; + + features = get_agreed_channelfeatures(tmpctx, channel->peer->ld->our_features, + channel->peer->their_features); + + copysig_or_zero(&bitcoin_signature[LOCAL], local_bitcoin_signature); + copysig_or_zero(&bitcoin_signature[REMOTE], remote_bitcoin_signature); + copysig_or_zero(&node_signature[LOCAL], local_node_signature); + copysig_or_zero(&node_signature[REMOTE], remote_node_signature); + node_id[LOCAL] = channel->peer->ld->id; + node_id[REMOTE] = channel->peer->id; + funding_pubkey[LOCAL] = channel->local_funding_pubkey; + funding_pubkey[REMOTE] = channel->channel_info.remote_fundingkey; + return create_channel_announcement_dir(ctx, features, scid, + node_signature, bitcoin_signature, node_id, funding_pubkey); +} + +u8 *unsigned_channel_update(const tal_t *ctx, + const struct channel *channel, + const struct short_channel_id *scid, + const u32 *old_timestamp, + bool forwardable, + bool enabled) +{ + struct lightningd *ld = channel->peer->ld; + secp256k1_ecdsa_signature dummy_sig; + u8 message_flags, channel_flags; + u32 timestamp; + + /* hsmd fills this in */ + memset(&dummy_sig, 0, sizeof(dummy_sig)); + /* BOLT #7: + + * The `channel_flags` bitfield is used to indicate the direction of + * the channel: it identifies the node that this update originated + * from and signals various options concerning the channel. The + * following table specifies the meaning of its individual bits: + * + * | Bit Position | Name | Meaning | + * | ------------- | ----------- | -------------------------------- | + * | 0 | `direction` | Direction this update refers to. | + * | 1 | `disable` | Disable the channel. | + */ + channel_flags = node_id_idx(&channel->peer->ld->id, + &channel->peer->id); + if (!enabled) + channel_flags |= ROUTING_FLAGS_DISABLED; + + /* BOLT #7: + * + * The `message_flags` bitfield is used to provide additional details + * about the message: + * + * | Bit Position | Name | + * | ------------- | ---------------| + * | 0 | `must_be_one` | + * | 1 | `dont_forward` | + */ + message_flags = 1; + if (!forwardable) + message_flags |= ROUTING_OPT_DONT_FORWARD; + + /* Make sure timestamp changes! */ + timestamp = time_now().ts.tv_sec; + /* FIXME: @endothermicdev points out that our clock could be + * wrong once, and now we'll keep producing future timestamps. + * We could sanity check that old_timestamp is within 2 weeks and + * discard? */ + if (old_timestamp && timestamp <= *old_timestamp) + timestamp = *old_timestamp + 1; + + return towire_channel_update(ctx, + &dummy_sig, + &chainparams->genesis_blockhash, + scid, + timestamp, + message_flags, + channel_flags, + ld->config.cltv_expiry_delta, + channel->htlc_minimum_msat, + channel->feerate_base, + channel->feerate_ppm, + channel->htlc_maximum_msat); +} + +/* Helper to get non-signature, non-timestamp parts of (valid!) channel_update */ +static void get_cupdate_parts(const u8 *channel_update, + const u8 *parts[2], + size_t sizes[2]) +{ + /* BOLT #7: + * + * 1. type: 258 (`channel_update`) + * 2. data: + * * [`signature`:`signature`] + * * [`chain_hash`:`chain_hash`] + * * [`short_channel_id`:`short_channel_id`] + * * [`u32`:`timestamp`] + *... + */ + /* Note: 2 bytes for `type` field */ + /* We already checked it's valid before accepting */ + assert(tal_count(channel_update) > 2 + 64 + 32 + 8 + 4); + parts[0] = channel_update + 2 + 64; + sizes[0] = 32 + 8; + parts[1] = channel_update + 2 + 64 + 32 + 8 + 4; + sizes[1] = tal_count(channel_update) - (64 + 2 + 32 + 8 + 4); +} + +bool channel_update_same(const u8 *cupdate1, const u8 *cupdate2) +{ + const u8 *parts1[2], *parts2[2]; + size_t sizes1[2], sizes2[2]; + + get_cupdate_parts(cupdate1, parts1, sizes1); + get_cupdate_parts(cupdate2, parts2, sizes2); + + return memeq(parts1[0], sizes1[0], parts2[0], sizes2[0]) + && memeq(parts1[1], sizes1[1], parts2[1], sizes2[1]); +} + +bool channel_update_details(const u8 *channel_update, + u32 *timestamp, + bool *enabled) +{ + u16 cltv_expiry_delta; + struct amount_msat htlc_minimum, htlc_maximum; + u32 fee_base_msat, fee_proportional_millionths, tstamp; + u8 message_flags, channel_flags; + secp256k1_ecdsa_signature signature; + struct bitcoin_blkid chain_hash; + struct short_channel_id short_channel_id; + + if (!fromwire_channel_update(channel_update, + &signature, &chain_hash, + &short_channel_id, &tstamp, + &message_flags, &channel_flags, + &cltv_expiry_delta, + &htlc_minimum, + &fee_base_msat, + &fee_proportional_millionths, + &htlc_maximum)) + return false; + + if (timestamp) + *timestamp = tstamp; + if (enabled) + *enabled = !(channel_flags & ROUTING_FLAGS_DISABLED); + return true; +} + +const char *check_announce_sigs(const struct channel *channel, + struct short_channel_id scid, + const secp256k1_ecdsa_signature *remote_node_signature, + const secp256k1_ecdsa_signature *remote_bitcoin_signature) +{ + struct sha256_double hash; + const u8 *cannounce; + + cannounce = create_channel_announcement(tmpctx, channel, scid, + NULL, NULL, NULL, NULL); + + /* BOLT #7: + * + * - MUST compute the double-SHA256 hash `h` of the message, beginning + * at offset 256, up to the end of the message. + * - Note: the hash skips the 4 signatures but hashes the rest of the + * message, including any future fields appended to the end. + */ + /* First two bytes are the msg type */ + int offset = 258; + sha256_double(&hash, cannounce + offset, tal_count(cannounce) - offset); + + if (!check_signed_hash_nodeid(&hash, remote_node_signature, + &channel->peer->id)) + return "invalid node_signature"; + + if (!check_signed_hash(&hash, remote_bitcoin_signature, + &channel->channel_info.remote_fundingkey)) + return "invalid bitcoin_signature"; + + return NULL; +} + +/* 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[3], + size_t sizes[3]) +{ + size_t len, ad_len; + const u8 *flen, *ad_start; + + /* BOLT #7: + * + * 1. type: 257 (`node_announcement`) + * 2. data: + * * [`signature`:`signature`] + * * [`u16`:`flen`] + * * [`flen*byte`:`features`] + * * [`u32`:`timestamp`] + *... + */ + /* Note: 2 bytes for `type` field */ + /* We already checked it's valid before accepting */ + assert(tal_count(node_announcement) > 2 + 64); + parts[0] = node_announcement + 2 + 64; + + /* Read flen to get size */ + flen = parts[0]; + len = tal_count(node_announcement) - (2 + 64); + 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; + + /* 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; +} + +/* Get timestamp of a (valid!) node_announcement */ +static u32 get_nannounce_timestamp(const u8 *node_announcement) +{ + const u8 *p; + u16 flen; + size_t len; + u32 timestamp; + + /* BOLT #7: + * + * 1. type: 257 (`node_announcement`) + * 2. data: + * * [`signature`:`signature`] + * * [`u16`:`flen`] + * * [`flen*byte`:`features`] + * * [`u32`:`timestamp`] + *... + */ + len = tal_count(node_announcement); + p = node_announcement; + + /* Note: 2 bytes for `type` field */ + fromwire_u16(&p, &len); + fromwire(&p, &len, NULL, 64); + flen = fromwire_u16(&p, &len); + fromwire(&p, &len, NULL, flen); + + timestamp = fromwire_u32(&p, &len); + assert(p != NULL); + + return timestamp; +} + +/* Is nann1 same as nann2 (not sigs and timestamps)? */ +bool node_announcement_same(const u8 *nann1, const u8 *nann2) +{ + const u8 *parts1[3], *parts2[3]; + size_t sizes1[3], sizes2[3]; + + get_nannounce_parts(nann1, parts1, sizes1); + get_nannounce_parts(nann2, parts2, sizes2); + + return memeq(parts1[0], sizes1[0], parts2[0], sizes2[0]) + && memeq(parts1[1], sizes1[1], parts2[1], sizes2[1]) + && memeq(parts1[2], sizes1[2], parts2[2], sizes2[2]); +} + +static u8 *create_nannounce(const tal_t *ctx, + struct lightningd *ld, + const secp256k1_ecdsa_signature *sig, + const struct wireaddr *addrs, + u32 timestamp, + const struct lease_rates *rates) +{ + u8 *addresses = tal_arr(tmpctx, u8, 0); + u8 *announcement; + struct tlv_node_ann_tlvs *na_tlv; + + for (size_t i = 0; i < tal_count(addrs); i++) + towire_wireaddr(&addresses, &addrs[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, + ld->our_features->bits[NODE_ANNOUNCE_FEATURE], + timestamp, + &ld->id, ld->rgb, ld->alias, + addresses, + na_tlv); + return announcement; +} + +/* Return an array of wireaddr to announce */ +static const struct wireaddr *gather_addresses(const tal_t *ctx, + struct lightningd *ld) +{ + struct wireaddr *addrs; + + /* Note: If ld->announceable is NULL, tal_dup_talarr returns NULL! */ + addrs = tal_dup_talarr(ctx, struct wireaddr, ld->announceable); + if (!addrs) + addrs = tal_arr(ctx, struct wireaddr, 0); + + /* Add discovered IPs v4/v6 verified by peer `remote_addr` feature. */ + /* Only do that if we don't have any addresses announced or + * `config.ip_discovery` is explicitly enabled. */ + switch (ld->config.ip_discovery) { + case OPT_AUTOBOOL_FALSE: + return addrs; + case OPT_AUTOBOOL_TRUE: + break; + case OPT_AUTOBOOL_AUTO: + if (tal_count(addrs) != 0) + return addrs; + break; + } + + if (ld->discovered_ip_v4) + tal_arr_expand(&addrs, *ld->discovered_ip_v4); + if (ld->discovered_ip_v6) + tal_arr_expand(&addrs, *ld->discovered_ip_v6); + + return addrs; +} + +u8 *unsigned_node_announcement(const tal_t *ctx, + struct lightningd *ld, + const u8 *prev) +{ + secp256k1_ecdsa_signature sig; + const struct wireaddr *addrs; + u32 timestamp = time_now().ts.tv_sec; + + addrs = gather_addresses(tmpctx, ld); + /* Even if we're quick, don't duplicate timestamps! */ + if (prev) { + u32 old_timestamp = get_nannounce_timestamp(prev); + if (timestamp <= old_timestamp) + timestamp = old_timestamp + 1; + } + + memset(&sig, 0, sizeof(sig)); + return create_nannounce(tmpctx, ld, &sig, + addrs, timestamp, + ld->lease_rates); +} + +void add_node_announcement_sig(u8 *nannounce, + const secp256k1_ecdsa_signature *sig) +{ + u8 compact[64]; + + secp256k1_ecdsa_signature_serialize_compact(secp256k1_ctx, compact, sig); + + /* BOLT #7: + * + * 1. type: 257 (`node_announcement`) + * 2. data: + * * [`signature`:`signature`] + */ + /* First two bytes are type */ + assert(tal_count(nannounce) > 2 + sizeof(compact)); + memcpy(nannounce + 2, compact, sizeof(compact)); +} diff --git a/lightningd/gossip_generation.h b/lightningd/gossip_generation.h new file mode 100644 index 000000000000..85d08592481b --- /dev/null +++ b/lightningd/gossip_generation.h @@ -0,0 +1,105 @@ +#ifndef LIGHTNING_LIGHTNINGD_GOSSIP_GENERATION_H +#define LIGHTNING_LIGHTNINGD_GOSSIP_GENERATION_H +#include "config.h" +#include +#include + +struct channel; + +/** + * create_channel_announcement: create a channel_announcement message + * @ctx: the tal context to allocate return from + * @channel: the channel to announce + * @scid: channel->scid + * @local_node_signature: optional local node signature + * @local_bitcoin_signature: optional local node signature + * @remote_node_signature: optional peer node signature + * @remote_bitcoin_signature: optional peer node signature + * + * The signatures are optional in case you're creating it to sign (or + * validate). + */ +u8 *create_channel_announcement(const tal_t *ctx, + const struct channel *channel, + struct short_channel_id scid, + const secp256k1_ecdsa_signature *local_node_signature, + const secp256k1_ecdsa_signature *local_bitcoin_signature, + const secp256k1_ecdsa_signature *remote_node_signature, + const secp256k1_ecdsa_signature *remote_bitcoin_signature); + +/** + * unsigned_channel_update: create a channel_update message with zeroed sig + * @ctx: the tal context to allocate return from + * @channel: the channel to announce + * @scid: the short_channel_id to sign + * @old_timestamp: optional timestamp of previous channel_update to replace. + * @forwardable: is this channel_update non-public? + * @enabled: sets channel_update's disabled flag + */ +u8 *unsigned_channel_update(const tal_t *ctx, + const struct channel *channel, + const struct short_channel_id *scid, + const u32 *old_timestamp, + bool forwardable, + bool enabled); + +/** + * channel_update_same: are these two channel updates the same? + * + * Ignoring timestamp and signatures. Basically, is it redundant? + */ +bool channel_update_same(const u8 *cupdate1, const u8 *cupdate2); + +/** + * channel_update_details: extract timestamp and/or enabled flag. + * @channel_update: the channel update, or NULL. + * @timestamp: where to extract the timestamp, or NULL. + * @enabled: where to extract the enabled flag, or NULL. + * + * Returns false (and doesn't touch @timestamp or @enabled) if + * channel_update NULL or invalid. + */ +bool channel_update_details(const u8 *channel_update, + u32 *timestamp, + bool *enabled); + +/** + * check_announce_sigs: check that signatures are correct for this scid + * @channel: the channel (for peer's id / bitcoin key and the channel features) + * @scid: the short_channel_id it's proposing + * @remote_node_signature: node signature + * @remote_bitcoin_signature: bitcoin signature + * + * Returns a string literal if one signature is bad. + */ +const char *check_announce_sigs(const struct channel *channel, + struct short_channel_id scid, + const secp256k1_ecdsa_signature *remote_node_signature, + const secp256k1_ecdsa_signature *remote_bitcoin_signature); + +/** + * unsigned_node_announcement: create a current unsigned node announcement. + * @ctx: the context to allocate return from + * @ld: the lightningd struct. + * @prev: optional previous announcement (to ensure we increase timestamp!) + */ +u8 *unsigned_node_announcement(const tal_t *ctx, + struct lightningd *ld, + const u8 *prev); + +/** + * add_node_announcement_sig: apply the signature to the node announcement + * @nannounce: the (unsigned) node announcement + * @sig: the signature (from hsm) + */ +void add_node_announcement_sig(u8 *nannounce, + const secp256k1_ecdsa_signature *sig); + +/** + * node_announcement_same: are these two node_announcements the same? + * + * Ignoring timestamp and signatures. Basically, is it redundant? + */ +bool node_announcement_same(const u8 *nann1, const u8 *nann2); + +#endif /* LIGHTNING_LIGHTNINGD_GOSSIP_GENERATION_H */ diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index d8120f4e2fd4..3913f364ea55 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -67,6 +67,7 @@ #include #include #include +#include #include #include #include @@ -235,8 +236,8 @@ static struct lightningd *new_lightningd(const tal_t *ctx) * so we disable this by default for now. */ ld->announce_dns = false; - ld->remote_addr_v4 = NULL; - ld->remote_addr_v6 = NULL; + ld->lease_rates = NULL; + ld->node_announcement = NULL; ld->discovered_ip_v4 = NULL; ld->discovered_ip_v6 = NULL; ld->listen = true; @@ -245,6 +246,7 @@ static struct lightningd *new_lightningd(const tal_t *ctx) ld->try_reexec = false; ld->recover_secret = NULL; ld->db_upgrade_ok = NULL; + ld->num_startup_connects = 0; /* --experimental-upgrade-protocol */ ld->experimental_upgrade_protocol = false; @@ -755,6 +757,7 @@ void notify_new_block(struct lightningd *ld, u32 block_height) /* Inform our subcomponents individually. */ htlcs_notify_new_block(ld, block_height); channel_notify_new_block(ld, block_height); + channel_gossip_notify_new_block(ld, block_height); gossip_notify_new_block(ld, block_height); waitblockheight_notify_new_block(ld, block_height); } diff --git a/lightningd/lightningd.h b/lightningd/lightningd.h index f823f59e7e1c..c344a4a0304c 100644 --- a/lightningd/lightningd.h +++ b/lightningd/lightningd.h @@ -172,6 +172,9 @@ struct lightningd { /* Do we want to reconnect to other peers? */ bool reconnect; + /* How many outstanding startup connection attempts? */ + size_t num_startup_connects; + /* Do we want to listen for other peers? */ bool listen; @@ -183,19 +186,19 @@ struct lightningd { /* Setup: And the bitset for each, whether to listen, announce or both */ enum addr_listen_announce *proposed_listen_announce; - /* Actual bindings and announceables from gossipd */ + /* Actual bindings and announceables from connectd */ struct wireaddr_internal *binding; struct wireaddr *announceable; - /* unverified remote_addr as reported by recent peers */ - struct wireaddr *remote_addr_v4; - struct wireaddr *remote_addr_v6; - struct node_id remote_addr_v4_peer; - struct node_id remote_addr_v6_peer; + /* Current node announcement (if any) */ + const u8 *node_announcement; + + /* Lease rates to advertize, set by json_setleaserates */ + struct lease_rates *lease_rates; - /* verified discovered IPs to be used for anouncement */ - struct wireaddr *discovered_ip_v4; - struct wireaddr *discovered_ip_v6; + /* Popular discovered IPs to be used for announcement */ + const struct wireaddr *discovered_ip_v4; + const struct wireaddr *discovered_ip_v6; /* Bearer of all my secrets. */ int hsm_fd; diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index d7bcde5eb652..22a92107d356 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -112,7 +112,7 @@ wallet_commit_channel(struct lightningd *ld, s64 final_key_idx; u64 static_remotekey_start; u32 lease_start_blockheight = 0; /* No leases on v1 */ - struct short_channel_id *alias_local; + struct short_channel_id local_alias; struct timeabs timestamp; bool any_active = peer_any_channel(uc->peer, channel_state_wants_peercomms, NULL); @@ -174,8 +174,8 @@ wallet_commit_channel(struct lightningd *ld, else static_remotekey_start = 0x7FFFFFFFFFFFFFFF; - alias_local = tal(NULL, struct short_channel_id); - randombytes_buf(alias_local, sizeof(struct short_channel_id)); + /* This won't clash, we don't even bother checking */ + randombytes_buf(&local_alias, sizeof(local_alias)); channel = new_channel(uc->peer, uc->dbid, NULL, /* No shachain yet */ @@ -194,7 +194,7 @@ wallet_commit_channel(struct lightningd *ld, local_funding, false, /* !remote_channel_ready */ NULL, /* no scid yet */ - alias_local, /* But maybe we have an alias we want to use? */ + &local_alias, NULL, /* They haven't told us an alias yet */ cid, /* The three arguments below are msatoshi_to_us, @@ -235,7 +235,8 @@ wallet_commit_channel(struct lightningd *ld, ld->config.htlc_minimum_msat, ld->config.htlc_maximum_msat, ld->config.ignore_fee_limits, - NULL); + NULL, + 0); /* Now we finally put it in the database. */ wallet_channel_insert(ld->wallet, channel); @@ -1504,7 +1505,11 @@ static struct channel *stub_chan(struct command *cmd, ld->config.htlc_minimum_msat, ld->config.htlc_maximum_msat, false, - NULL); + NULL, + 0); + + /* We don't want to gossip about this, ever. */ + channel->channel_gossip = tal_free(channel->channel_gossip); return channel; } diff --git a/lightningd/pay.c b/lightningd/pay.c index 1e759c7fdaa0..fa0dddc61d46 100644 --- a/lightningd/pay.c +++ b/lightningd/pay.c @@ -808,7 +808,7 @@ find_channel_for_htlc_add(struct lightningd *ld, const struct amount_msat *amount) { struct channel *channel; - struct short_channel_id *scid; + const struct short_channel_id *scid; struct peer *peer = peer_by_id(ld, node); if (!peer) return NULL; @@ -843,7 +843,7 @@ find_channel_for_htlc_add(struct lightningd *ld, return NULL; found: - scid = channel->scid ? channel->scid : channel->alias[LOCAL]; + scid = channel_scid_or_local_alias(channel); log_debug( ld->log, "Selected channel %s (%s) for selector %s (%s)", short_channel_id_to_str(tmpctx, scid), diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 64753c0f13bf..0feeade9e9cd 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -816,12 +818,16 @@ static void json_add_channel(struct lightningd *ld, struct amount_msat funding_msat; struct amount_sat peer_funded_sats; struct state_change_entry *state_changes; + const struct peer_update *peer_update; u32 feerate; json_object_start(response, key); if (peer) { json_add_node_id(response, "peer_id", &peer->id); json_add_bool(response, "peer_connected", peer->connected == PEER_CONNECTED); + if (peer->connected == PEER_CONNECTED) { + json_add_bool(response, "reestablished", channel->reestablished); + } json_add_channel_type(response, "channel_type", channel->type); if (channel->ignore_fee_limits) { json_add_bool(response, "ignore_fee_limits", channel->ignore_fee_limits); @@ -841,22 +847,29 @@ static void json_add_channel(struct lightningd *ld, json_add_u32(response, "fee_proportional_millionths", channel->feerate_ppm); json_object_end(response); - if (channel->peer_update) { + + peer_update = channel_gossip_get_remote_update(channel); + if (peer_update) { json_object_start(response, "remote"); json_add_amount_msat(response, "htlc_minimum_msat", - channel->peer_update->htlc_minimum_msat); + peer_update->htlc_minimum_msat); json_add_amount_msat(response, "htlc_maximum_msat", - channel->peer_update->htlc_maximum_msat); - json_add_u32(response, "cltv_expiry_delta", channel->peer_update->cltv_delta); + peer_update->htlc_maximum_msat); + json_add_u32(response, "cltv_expiry_delta", peer_update->cltv_delta); json_add_amount_msat(response, "fee_base_msat", - amount_msat(channel->peer_update->fee_base)); + amount_msat(peer_update->fee_base)); json_add_u32(response, "fee_proportional_millionths", - channel->peer_update->fee_ppm); + peer_update->fee_ppm); json_object_end(response); } json_object_end(response); + + if (channel->last_stable_connection != 0) { + json_add_u64(response, "last_stable_connection", + channel->last_stable_connection); + } } json_add_string(response, "state", channel_state_name(channel)); @@ -1318,9 +1331,13 @@ static void connect_activate_subd(struct lightningd *ld, struct channel *channel tal_hex(tmpctx, error)); /* Get connectd to send error and close. */ subd_send_msg(ld->connectd, - take(towire_connectd_peer_final_msg(NULL, &channel->peer->id, - channel->peer->connectd_counter, - error))); + take(towire_connectd_peer_send_msg(NULL, &channel->peer->id, + channel->peer->connectd_counter, + error))); + subd_send_msg(ld->connectd, + take(towire_connectd_discard_peer(NULL, + &channel->peer->id, + channel->peer->connectd_counter))); } static void peer_connected_hook_final(struct peer_connected_hook_payload *payload STEALS) @@ -1367,12 +1384,16 @@ static void peer_connected_hook_final(struct peer_connected_hook_payload *payloa /* Developer hack to fail all channels on permfail line. */ if (dev_disconnect_permanent(ld)) { list_for_each(&peer->channels, channel, list) { + subd_send_msg(ld->connectd, + take(towire_connectd_peer_send_msg(NULL, &peer->id, + peer->connectd_counter, + channel->error))); + subd_send_msg(ld->connectd, + take(towire_connectd_discard_peer(NULL, + &peer->id, + peer->connectd_counter))); channel_fail_permanent(channel, REASON_LOCAL, "dev_disconnect permfail"); - subd_send_msg(ld->connectd, - take(towire_connectd_peer_final_msg(NULL, &peer->id, - peer->connectd_counter, - channel->error))); } return; } @@ -1387,6 +1408,7 @@ static void peer_connected_hook_final(struct peer_connected_hook_payload *payloa connect_activate_subd(ld, channel); } } + return; send_error: @@ -1394,9 +1416,13 @@ static void peer_connected_hook_final(struct peer_connected_hook_payload *payloa tal_hex(tmpctx, error)); /* Get connectd to send error and close. */ subd_send_msg(ld->connectd, - take(towire_connectd_peer_final_msg(NULL, &peer->id, - peer->connectd_counter, - error))); + take(towire_connectd_peer_send_msg(NULL, &peer->id, + peer->connectd_counter, + error))); + subd_send_msg(ld->connectd, + take(towire_connectd_discard_peer(NULL, + &peer->id, + peer->connectd_counter))); } static bool @@ -1444,72 +1470,174 @@ peer_connected_hook_deserialize(struct peer_connected_hook_payload *payload, return true; } -/* Compare and store `remote_addr` and the `peer_id` that reported it. - * If new address was reported by at least one other, do node_announcement */ -static void update_remote_addr(struct lightningd *ld, - const struct wireaddr *remote_addr, - const struct node_id peer_id) +/* Have they/we committed funds to the channel? */ +static bool channel_state_relationship(enum channel_state state) +{ + switch (state) { + case DUALOPEND_OPEN_INIT: + case DUALOPEND_OPEN_COMMIT_READY: + case DUALOPEND_OPEN_COMMITTED: + case DUALOPEND_AWAITING_LOCKIN: + case CHANNELD_AWAITING_LOCKIN: + return false; + case CLOSINGD_COMPLETE: + case AWAITING_UNILATERAL: + case FUNDING_SPEND_SEEN: + case ONCHAIN: + case CLOSED: + case CHANNELD_NORMAL: + case CHANNELD_AWAITING_SPLICE: + case CLOSINGD_SIGEXCHANGE: + case CHANNELD_SHUTTING_DOWN: + return true; + } + + abort(); +} + +/* We choose the most popular address we've given (if at least 2 give + * it), prefering peers which have a channel with us */ +struct discovered_addr { + bool preferred; + /* Port is uniformly set to our configured port in here. */ + struct wireaddr addr; +}; + +static int daddr_cmp(const struct discovered_addr *a, + const struct discovered_addr *b, + void *unused) +{ + return wireaddr_cmp_type(&a->addr, &b->addr, NULL); +} + +static const struct wireaddr *best_remote_addr(const tal_t *ctx, + struct lightningd *ld, + enum wire_addr_type atype) +{ + struct peer *peer; + struct peer_node_id_map_iter it; + struct discovered_addr *daddrs; + const struct wireaddr *best, *prev; + size_t best_score, cur_score, preferred_bonus; + + daddrs = tal_arr(tmpctx, struct discovered_addr, 0); + for (peer = peer_node_id_map_first(ld->peers, &it); + peer; + peer = peer_node_id_map_next(ld->peers, &it)) { + struct discovered_addr daddr; + if (!peer->remote_addr) + continue; + if (peer->remote_addr->type != atype) + continue; + daddr.preferred = peer_any_channel(peer, + channel_state_relationship, + NULL); + daddr.addr = *peer->remote_addr; + daddr.addr.port = ld->config.ip_discovery_port; + log_debug(ld->log, "best_remote_addr: peer %s gave addr %s (%s)", + type_to_string(tmpctx, struct node_id, &peer->id), + fmt_wireaddr(tmpctx, &daddr.addr), + daddr.preferred ? "preferred" : "no chan"); + tal_arr_expand(&daddrs, daddr); + } + + /* Sort into matching addresses */ + asort(daddrs, tal_count(daddrs), daddr_cmp, NULL); + + /* All the non-preferred peers cannot outvote 1 preferred peer */ + preferred_bonus = tal_count(daddrs); + best_score = cur_score = 0; + best = prev = NULL; + for (size_t i = 0; i < tal_count(daddrs); i++) { + if (prev && !wireaddr_eq(prev, &daddrs[i].addr)) { + if (cur_score > best_score) { + best_score = cur_score; + best = prev; + } + cur_score = 0; + } + cur_score += daddrs[i].preferred ? preferred_bonus : 1; + prev = &daddrs[i].addr; + } + if (cur_score > best_score) { + best_score = cur_score; + best = prev; + } + + if (!best) { + log_debug(ld->log, + "node_address: no peers gave remote addresses"); + return NULL; + } + + /* Does it agree with what we already know? */ + if (wireaddr_arr_contains(ld->announceable, best)) { + log_debug(ld->log, + "node_address: best address already being announced"); + return NULL; + } + + /* This means we got it from one preferred peer and at least one other */ + if (best_score > preferred_bonus) { + log_debug(ld->log, + "node_address: %zu peers gave remote addresses," + " best score %zu (preferred)", + tal_count(daddrs), best_score); + return tal_dup(ctx, struct wireaddr, best); + } + + /* No preferred peers gave us addresses? Use > 1 untrusted */ + if (best_score < preferred_bonus && best_score > 1) { + log_debug(ld->log, + "node_address: %zu peers gave remote addresses," + " best score %zu (no preferred)", + tal_count(daddrs), best_score); + return tal_dup(ctx, struct wireaddr, best); + } + + log_debug(ld->log, + "node_address: %zu peers gave remote addresses," + " best score %zu: not using", + tal_count(daddrs), best_score); + return NULL; +} + +/* Consider `remote_addr` from peer: if it could change things, reconsider + * what our discoverd IP is. Returns new address, or NULL. */ +static const struct wireaddr *update_remote_addr(struct lightningd *ld, + const struct wireaddr *remote_addr) { /* failsafe to prevent privacy leakage. */ if (ld->always_use_proxy || ld->config.ip_discovery == OPT_AUTOBOOL_FALSE) - return; + return NULL; switch (remote_addr->type) { case ADDR_TYPE_IPV4: - /* init pointers first time */ - if (ld->remote_addr_v4 == NULL) { - ld->remote_addr_v4 = tal_dup(ld, struct wireaddr, - remote_addr); - ld->remote_addr_v4_peer = peer_id; - } - /* if updated by the same peer just remember the latest addr */ - if (node_id_eq(&ld->remote_addr_v4_peer, &peer_id)) { - *ld->remote_addr_v4 = *remote_addr; - break; + /* If it's telling us what we already know, don't reevaluate */ + if (!ld->discovered_ip_v4 + || !wireaddr_eq(ld->discovered_ip_v4, remote_addr)) { + ld->discovered_ip_v4 = tal_free(ld->discovered_ip_v4); + ld->discovered_ip_v4 = best_remote_addr(ld, ld, ADDR_TYPE_IPV4); + return ld->discovered_ip_v4; } - /* tell gossip we have a valid update */ - if (wireaddr_eq_without_port(ld->remote_addr_v4, remote_addr)) { - ld->discovered_ip_v4 = tal_dup(ld, struct wireaddr, - ld->remote_addr_v4); - ld->discovered_ip_v4->port = ld->config.ip_discovery_port; - subd_send_msg(ld->gossip, towire_gossipd_discovered_ip( - tmpctx, - ld->discovered_ip_v4)); - } - /* store latest values */ - *ld->remote_addr_v4 = *remote_addr; - ld->remote_addr_v4_peer = peer_id; - break; + return NULL; case ADDR_TYPE_IPV6: - /* same code :s/4/6/ without the comments ;) */ - if (ld->remote_addr_v6 == NULL) { - ld->remote_addr_v6 = tal_dup(ld, struct wireaddr, - remote_addr); - ld->remote_addr_v6_peer = peer_id; + /* If it's telling us what we already know, don't reevaluate */ + if (!ld->discovered_ip_v6 + || !wireaddr_eq(ld->discovered_ip_v6, remote_addr)) { + ld->discovered_ip_v6 = tal_free(ld->discovered_ip_v6); + ld->discovered_ip_v6 = best_remote_addr(ld, ld, ADDR_TYPE_IPV6); + return ld->discovered_ip_v6; } - if (node_id_eq(&ld->remote_addr_v6_peer, &peer_id)) { - *ld->remote_addr_v6 = *remote_addr; - break; - } - if (wireaddr_eq_without_port(ld->remote_addr_v6, remote_addr)) { - ld->discovered_ip_v6 = tal_dup(ld, struct wireaddr, - ld->remote_addr_v6); - ld->discovered_ip_v6->port = ld->config.ip_discovery_port; - subd_send_msg(ld->gossip, towire_gossipd_discovered_ip( - tmpctx, - ld->discovered_ip_v6)); - } - *ld->remote_addr_v6 = *remote_addr; - ld->remote_addr_v6_peer = peer_id; - break; - + return NULL; /* ignore all other cases */ case ADDR_TYPE_TOR_V2_REMOVED: case ADDR_TYPE_TOR_V3: case ADDR_TYPE_DNS: - break; + return NULL; } + abort(); } REGISTER_PLUGIN_HOOK(peer_connected, @@ -1572,9 +1700,7 @@ void peer_connected(struct lightningd *ld, const u8 *msg) /* Update peer address and direction */ peer->addr = hook_payload->addr; peer->connected_incoming = hook_payload->incoming; - if (peer->remote_addr) - tal_free(peer->remote_addr); - peer->remote_addr = NULL; + peer->remote_addr = tal_free(peer->remote_addr); hook_payload->peer_id = id; /* If there's a connect command, use its id as basis for hook id */ @@ -1582,14 +1708,18 @@ void peer_connected(struct lightningd *ld, const u8 *msg) /* Log and update remote_addr for Nat/IP discovery. */ if (hook_payload->remote_addr) { + const struct wireaddr *best; log_peer_debug(ld->log, &id, "Peer says it sees our address as: %s", fmt_wireaddr(tmpctx, hook_payload->remote_addr)); peer->remote_addr = tal_dup(peer, struct wireaddr, hook_payload->remote_addr); - /* Currently only from peers we have a channel with, until we - * do stuff like probing for remote_addr to a random node. */ - if (!list_empty(&peer->channels)) - update_remote_addr(ld, hook_payload->remote_addr, id); + best = update_remote_addr(ld, peer->remote_addr); + if (best) { + log_debug(ld->log, + "Update our node_announcement for discovered address: %s", + fmt_wireaddr(tmpctx, best)); + channel_gossip_node_announce(ld); + } } plugin_hook_call_peer_connected(ld, cmd_id, hook_payload); @@ -1764,9 +1894,13 @@ void peer_spoke(struct lightningd *ld, const u8 *msg) tal_hex(tmpctx, error)); /* Get connectd to send error and close. */ subd_send_msg(ld->connectd, - take(towire_connectd_peer_final_msg(NULL, &peer->id, - peer->connectd_counter, - error))); + take(towire_connectd_peer_send_msg(NULL, &peer->id, + peer->connectd_counter, + error))); + subd_send_msg(ld->connectd, + take(towire_connectd_discard_peer(NULL, + &peer->id, + peer->connectd_counter))); return; tell_connectd: @@ -1806,9 +1940,13 @@ void peer_disconnect_done(struct lightningd *ld, const u8 *msg) * and not free when no more channels. */ p = peer_by_id(ld, &id); if (p) { + struct channel *channel; assert(p->connectd_counter == connectd_counter); log_peer_debug(ld->log, &id, "peer_disconnect_done"); p->connected = PEER_DISCONNECTED; + + list_for_each(&p->channels, channel, list) + channel_gossip_channel_disconnect(channel); } /* If you were trying to connect, it failed. */ @@ -1988,6 +2126,8 @@ static enum watch_result funding_depth_cb(struct lightningd *ld, return DELETE_WATCH; case CHANNELD_AWAITING_LOCKIN: + /* This may be redundant, and may be public later, but + * make sure we tell gossipd at least once */ if (depth >= channel->minimum_depth && channel->remote_channel_ready) { lockin_complete(channel, CHANNELD_AWAITING_LOCKIN); @@ -1996,6 +2136,7 @@ static enum watch_result funding_depth_cb(struct lightningd *ld, case CHANNELD_NORMAL: case CHANNELD_AWAITING_SPLICE: channeld_tell_depth(channel, txid, depth); + if (depth < ANNOUNCE_MIN_DEPTH || depth < channel->minimum_depth) return KEEP_WATCHING; /* Normal state and past announce depth? Stop bothering us! */ @@ -2357,6 +2498,8 @@ static void setup_peer(struct peer *peer, u32 delay) /* Make sure connectd knows to try reconnecting. */ if (connect) { + ld->num_startup_connects++; + /* To delay, make it seem like we just connected. */ if (delay > 0) { peer->reconnect_delay = delay; @@ -2379,6 +2522,10 @@ void setup_peers(struct lightningd *ld) setup_peer(p, delay > 0 ? delay : 0); delay++; } + + /* In case there are no peers at all to connect to */ + if (ld->num_startup_connects == 0) + channel_gossip_startup_done(ld); } /* Pull peers, channels and HTLCs from db, and wire them up. */ @@ -2904,10 +3051,6 @@ static void set_channel_config(struct command *cmd, struct channel *channel, channel_update_feerates(cmd->ld, channel); } - /* Tell gossipd */ - /* FIXME: this always enables channel, even if not enabled! */ - tell_gossipd_local_channel_update(cmd->ld, channel, true); - /* save values to database */ wallet_channel_save(cmd->ld->wallet, channel); diff --git a/lightningd/peer_htlcs.c b/lightningd/peer_htlcs.c index 36b81760915c..2cd4e289f428 100644 --- a/lightningd/peer_htlcs.c +++ b/lightningd/peer_htlcs.c @@ -491,7 +491,8 @@ static void destroy_hout_subd_died(struct htlc_out *hout) hout->key.id); hout->failmsg = towire_temporary_channel_failure(hout, - get_channel_update(hout->key.channel)); + channel_update_for_error(tmpctx, + hout->key.channel)); /* Assign a temporary state (we're about to free it!) so checks * are happy that it has a failure message */ @@ -529,7 +530,7 @@ static void rcvd_htlc_reply(struct subd *subd, const u8 *msg, const int *fds UNU if (tal_count(failmsg)) { /* It's our job to append the channel_update */ if (fromwire_peektype(failmsg) & UPDATE) { - const u8 *update = get_channel_update(hout->key.channel); + const u8 *update = channel_update_for_error(tmpctx, hout->key.channel); towire(&failmsg, update, tal_bytelen(update)); } hout->failmsg = tal_steal(hout, failmsg); @@ -626,7 +627,7 @@ const u8 *send_htlc_out(const tal_t *ctx, log_info(out->log, "Attempt to send HTLC but unowned (%s)", channel_state_name(out)); return towire_temporary_channel_failure(ctx, - get_channel_update(out)); + channel_update_for_error(tmpctx, out)); } if (!topology_synced(out->peer->ld->topology)) { @@ -749,7 +750,8 @@ static void forward_htlc(struct htlc_in *hin, next->old_feerate_base, next->old_feerate_ppm)) { failmsg = towire_fee_insufficient(tmpctx, hin->msat, - get_channel_update(next)); + channel_update_for_error(tmpctx, + next)); goto fail; } log_info(hin->key.channel->log, @@ -763,7 +765,7 @@ static void forward_htlc(struct htlc_in *hin, || amount_msat_less(amt_to_forward, next->old_htlc_minimum_msat) || amount_msat_greater(amt_to_forward, next->old_htlc_maximum_msat)) { failmsg = towire_temporary_channel_failure(tmpctx, - get_channel_update(next)); + channel_update_for_error(tmpctx, next)); goto fail; } log_info(hin->key.channel->log, @@ -773,7 +775,7 @@ static void forward_htlc(struct htlc_in *hin, if (!check_cltv(hin, cltv_expiry, outgoing_cltv_value, ld->config.cltv_expiry_delta)) { failmsg = towire_incorrect_cltv_expiry(tmpctx, cltv_expiry, - get_channel_update(next)); + channel_update_for_error(tmpctx, next)); goto fail; } @@ -792,7 +794,7 @@ static void forward_htlc(struct htlc_in *hin, outgoing_cltv_value, get_block_height(ld->topology)); failmsg = towire_expiry_too_soon(tmpctx, - get_channel_update(next)); + channel_update_for_error(tmpctx, next)); goto fail; } diff --git a/lightningd/test/run-check_node_announcement.c b/lightningd/test/run-check_node_announcement.c new file mode 100644 index 000000000000..76935e22db2a --- /dev/null +++ b/lightningd/test/run-check_node_announcement.c @@ -0,0 +1,72 @@ +#include "config.h" +#include "../gossip_generation.c" +#include +#include +#include +#include +#include +#include +#include + +/* AUTOGENERATED MOCKS START */ +/* Generated stub for check_signed_hash_nodeid */ +bool check_signed_hash_nodeid(const struct sha256_double *hash UNNEEDED, + const secp256k1_ecdsa_signature *signature UNNEEDED, + const struct node_id *id UNNEEDED) +{ fprintf(stderr, "check_signed_hash_nodeid called!\n"); abort(); } +/* Generated stub for fromwire_bigsize */ +bigsize_t fromwire_bigsize(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_bigsize called!\n"); abort(); } +/* Generated stub for fromwire_channel_id */ +bool 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_node_id */ +void fromwire_node_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct node_id *id UNNEEDED) +{ fprintf(stderr, "fromwire_node_id called!\n"); abort(); } +/* Generated stub for get_agreed_channelfeatures */ +u8 *get_agreed_channelfeatures(const tal_t *ctx UNNEEDED, + const struct feature_set *our_features UNNEEDED, + const u8 *theirfeatures UNNEEDED) +{ fprintf(stderr, "get_agreed_channelfeatures called!\n"); abort(); } +/* Generated stub for node_id_cmp */ +int node_id_cmp(const struct node_id *a UNNEEDED, const struct node_id *b UNNEEDED) +{ fprintf(stderr, "node_id_cmp 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_node_id */ +void towire_node_id(u8 **pptr UNNEEDED, const struct node_id *id UNNEEDED) +{ fprintf(stderr, "towire_node_id called!\n"); abort(); } +/* AUTOGENERATED MOCKS END */ + +int main(int argc, char *argv[]) +{ + u8 *ann, *ann2; + + common_setup(argv[0]); + + /* No TLV checks */ + ann = tal_hexdata(tmpctx, "01017d49b51b7d3772636c09901df78c81faa1a7f045e329366ad779ecbaf0cc07f764d8ffd3596ef6802fd0e4c5c180c74fb3dfb14aae493ed48d35a3df75c20eca00078000000802aaa260b14569022d223620a359a47ff7f7ac447c85c46c923da53389221a0054c11c1e3ca31d59022d2253494c454e544152544953542d3236352d67373833393533312d6d6f646465640000", strlen("01017d49b51b7d3772636c09901df78c81faa1a7f045e329366ad779ecbaf0cc07f764d8ffd3596ef6802fd0e4c5c180c74fb3dfb14aae493ed48d35a3df75c20eca00078000000802aaa260b14569022d223620a359a47ff7f7ac447c85c46c923da53389221a0054c11c1e3ca31d59022d2253494c454e544152544953542d3236352d67373833393533312d6d6f646465640000")); + ann2 = tal_hexdata(tmpctx, "01017d49b51b7d3772636c09901df78c81faa1a7f045e329366ad779ecbaf0cc07f764d8ffd3596ef6802fd0e4c5c180c74fb3dfb14aae493ed48d35a3df75c20eca00078000000802aaa260b14569022d223620a359a47ff7f7ac447c85c46c923da53389221a0054c11c1e3ca31d59022d2253494c454e544152544953542d3236352d67373833393533312d6d6f646465640000", strlen("01017d49b51b7d3772636c09901df78c81faa1a7f045e329366ad779ecbaf0cc07f764d8ffd3596ef6802fd0e4c5c180c74fb3dfb14aae493ed48d35a3df75c20eca00078000000802aaa260b14569022d223620a359a47ff7f7ac447c85c46c923da53389221a0054c11c1e3ca31d59022d2253494c454e544152544953542d3236352d67373833393533312d6d6f646465640000"));; + assert(node_announcement_same(ann, ann2)); + + ann2 = tal_hexdata(tmpctx, "01010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000078000000802aaa260b145790266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c035180266e453454e494f524245414d000000000000000000000000000000000000000000000000", strlen("01010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000078000000802aaa260b145790266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c035180266e453454e494f524245414d000000000000000000000000000000000000000000000000")); + assert(!node_announcement_same(ann, ann2)); + + /* TLV checks */ + ann = tal_hexdata(tmpctx, "0101069628d227649cc2823d94647ad08ea34ad24e7eea95b7a0249bc83e73efefa6072cab1841f0ef3e6d7f4c4140b7b1b13049eb0d85941d7d7bd30c921bfd550300078000000802aaa260b1496f0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c035180266e453454e494f524245414d000000000000000000000000000000000000000000000000010c0014000003e80096001607d0", strlen("0101069628d227649cc2823d94647ad08ea34ad24e7eea95b7a0249bc83e73efefa6072cab1841f0ef3e6d7f4c4140b7b1b13049eb0d85941d7d7bd30c921bfd550300078000000802aaa260b1496f0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c035180266e453454e494f524245414d000000000000000000000000000000000000000000000000010c0014000003e80096001607d0")); + ann2 = tal_hexdata(tmpctx, "0101069628d227649cc2823d94647ad08ea34ad24e7eea95b7a0249bc83e73efefa6072cab1841f0ef3e6d7f4c4140b7b1b13049eb0d85941d7d7bd30c921bfd550300078000000802aaa260b1496f0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c035180266e453454e494f524245414d000000000000000000000000000000000000000000000000010c0014000003e80096001607d0", strlen("0101069628d227649cc2823d94647ad08ea34ad24e7eea95b7a0249bc83e73efefa6072cab1841f0ef3e6d7f4c4140b7b1b13049eb0d85941d7d7bd30c921bfd550300078000000802aaa260b1496f0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c035180266e453454e494f524245414d000000000000000000000000000000000000000000000000010c0014000003e80096001607d0")); + + assert(node_announcement_same(ann, ann2)); + + /* Tweak the last, check that it fails */ + ann[tal_count(ann) - 1]++; + assert(!node_announcement_same(ann, ann2)); + + common_shutdown(); + return 0; +} diff --git a/lightningd/test/run-find_my_abspath.c b/lightningd/test/run-find_my_abspath.c index ba8475fff6f6..94b7e527dad1 100644 --- a/lightningd/test/run-find_my_abspath.c +++ b/lightningd/test/run-find_my_abspath.c @@ -10,6 +10,10 @@ int unused_main(int argc, char *argv[]); /* Generated stub for begin_topology */ void begin_topology(struct chain_topology *topo UNNEEDED) { fprintf(stderr, "begin_topology called!\n"); abort(); } +/* Generated stub for channel_gossip_notify_new_block */ +void channel_gossip_notify_new_block(struct lightningd *ld UNNEEDED, + u32 block_height UNNEEDED) +{ fprintf(stderr, "channel_gossip_notify_new_block called!\n"); abort(); } /* Generated stub for channel_notify_new_block */ void channel_notify_new_block(struct lightningd *ld UNNEEDED, u32 block_height UNNEEDED) diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index afbe35775e30..a19c13e25462 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -84,6 +84,18 @@ void channel_fail_transient(struct channel *channel UNNEEDED, bool disconnect UNNEEDED, const char *fmt UNNEEDED, ...) { fprintf(stderr, "channel_fail_transient called!\n"); abort(); } +/* Generated stub for channel_gossip_channel_disconnect */ +void channel_gossip_channel_disconnect(struct channel *channel UNNEEDED) +{ fprintf(stderr, "channel_gossip_channel_disconnect called!\n"); abort(); } +/* Generated stub for channel_gossip_get_remote_update */ +const struct peer_update *channel_gossip_get_remote_update(const struct channel *channel UNNEEDED) +{ fprintf(stderr, "channel_gossip_get_remote_update called!\n"); abort(); } +/* Generated stub for channel_gossip_node_announce */ +void channel_gossip_node_announce(struct lightningd *ld UNNEEDED) +{ fprintf(stderr, "channel_gossip_node_announce called!\n"); abort(); } +/* Generated stub for channel_gossip_startup_done */ +void channel_gossip_startup_done(struct lightningd *ld UNNEEDED) +{ fprintf(stderr, "channel_gossip_startup_done called!\n"); abort(); } /* Generated stub for channel_has_htlc_in */ struct htlc_in *channel_has_htlc_in(struct channel *channel UNNEEDED) { fprintf(stderr, "channel_has_htlc_in called!\n"); abort(); } @@ -913,11 +925,6 @@ void subd_send_fd(struct subd *sd UNNEEDED, int fd UNNEEDED) /* Generated stub for subd_send_msg */ void subd_send_msg(struct subd *sd UNNEEDED, const u8 *msg_out UNNEEDED) { fprintf(stderr, "subd_send_msg called!\n"); abort(); } -/* Generated stub for tell_gossipd_local_channel_update */ -void tell_gossipd_local_channel_update(struct lightningd *ld UNNEEDED, - struct channel *channel UNNEEDED, - bool enabled UNNEEDED) -{ fprintf(stderr, "tell_gossipd_local_channel_update 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(); } @@ -930,12 +937,15 @@ u8 *towire_channeld_dev_memleak(const tal_t *ctx UNNEEDED) /* Generated stub for towire_channeld_dev_reenable_commit */ u8 *towire_channeld_dev_reenable_commit(const tal_t *ctx UNNEEDED) { fprintf(stderr, "towire_channeld_dev_reenable_commit called!\n"); abort(); } +/* Generated stub for towire_connectd_discard_peer */ +u8 *towire_connectd_discard_peer(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, u64 counter UNNEEDED) +{ fprintf(stderr, "towire_connectd_discard_peer called!\n"); abort(); } /* Generated stub for towire_connectd_peer_connect_subd */ u8 *towire_connectd_peer_connect_subd(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, u64 counter UNNEEDED, const struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "towire_connectd_peer_connect_subd called!\n"); abort(); } -/* Generated stub for towire_connectd_peer_final_msg */ -u8 *towire_connectd_peer_final_msg(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, u64 counter UNNEEDED, const u8 *msg UNNEEDED) -{ fprintf(stderr, "towire_connectd_peer_final_msg called!\n"); abort(); } +/* Generated stub for towire_connectd_peer_send_msg */ +u8 *towire_connectd_peer_send_msg(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, u64 counter UNNEEDED, const u8 *msg UNNEEDED) +{ fprintf(stderr, "towire_connectd_peer_send_msg called!\n"); abort(); } /* Generated stub for towire_dualopend_dev_memleak */ u8 *towire_dualopend_dev_memleak(const tal_t *ctx UNNEEDED) { fprintf(stderr, "towire_dualopend_dev_memleak called!\n"); abort(); } @@ -944,9 +954,6 @@ u8 *towire_errorfmt(const tal_t *ctx UNNEEDED, const struct channel_id *channel UNNEEDED, const char *fmt UNNEEDED, ...) { fprintf(stderr, "towire_errorfmt called!\n"); abort(); } -/* Generated stub for towire_gossipd_discovered_ip */ -u8 *towire_gossipd_discovered_ip(const tal_t *ctx UNNEEDED, const struct wireaddr *discovered_ip UNNEEDED) -{ fprintf(stderr, "towire_gossipd_discovered_ip called!\n"); abort(); } /* Generated stub for towire_hsmd_preapprove_invoice */ u8 *towire_hsmd_preapprove_invoice(const tal_t *ctx UNNEEDED, const wirestring *invstring UNNEEDED) { fprintf(stderr, "towire_hsmd_preapprove_invoice called!\n"); abort(); } diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 1638c3539c82..8d1cf58d270c 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -227,6 +227,9 @@ struct state { /* Does this negotation require confirmed inputs? */ bool require_confirmed_inputs[NUM_SIDES]; + /* Our alias */ + struct short_channel_id local_alias; + bool dev_accept_any_channel_type; }; @@ -1563,7 +1566,7 @@ static u8 *handle_channel_ready(struct state *state, u8 *msg) /* We save when the peer locks, so we do the right * thing on reconnects */ if (!state->channel_ready[REMOTE]) { - msg = towire_dualopend_peer_locked(NULL, &remote_per_commit); + msg = towire_dualopend_peer_locked(NULL, &remote_per_commit, tlvs->short_channel_id); wire_sync_write(REQ_FD, take(msg)); } @@ -3869,6 +3872,7 @@ static void send_channel_ready(struct state *state) /* Figure out the next local commit */ hsm_per_commitment_point(1, &next_local_per_commit); + tlvs->short_channel_id = &state->local_alias; msg = towire_channel_ready(NULL, &state->channel_id, &next_local_per_commit, tlvs); peer_write(state->pps, take(msg)); @@ -3878,38 +3882,6 @@ static void send_channel_ready(struct state *state) billboard_update(state); } -/* FIXME: Maybe cache this? */ -static struct amount_sat channel_size(struct state *state) -{ - u32 funding_outnum; - const u8 *funding_wscript = - bitcoin_redeem_2of2(tmpctx, - &state->our_funding_pubkey, - &state->their_funding_pubkey); - - if (!find_txout(state->tx_state->psbt, - scriptpubkey_p2wsh(tmpctx, funding_wscript), - &funding_outnum)) { - open_err_fatal(state, "Cannot fund txout"); - } - - return psbt_output_get_amount(state->tx_state->psbt, funding_outnum); -} - -static void tell_gossipd_new_channel(struct state *state) -{ - u8 *msg; - const u8 *annfeatures = get_agreed_channelfeatures(tmpctx, - state->our_features, - state->their_features); - - /* Tell lightningd about local channel. */ - msg = towire_dualopend_local_private_channel(NULL, - channel_size(state), - annfeatures); - wire_sync_write(REQ_FD, take(msg)); -} - static u8 *handle_funding_depth(struct state *state, u8 *msg) { u32 depth; @@ -3924,9 +3896,6 @@ static u8 *handle_funding_depth(struct state *state, u8 *msg) /* We check this before we arrive here, but for sanity */ assert(state->minimum_depth <= depth); - /* Tell gossipd the new channel exists before we tell peer. */ - tell_gossipd_new_channel(state); - send_channel_ready(state); if (state->channel_ready[REMOTE]) return towire_dualopend_channel_locked(state); @@ -4207,7 +4176,6 @@ static u8 *handle_master_in(struct state *state) case WIRE_DUALOPEND_FAIL_FALLEN_BEHIND: case WIRE_DUALOPEND_DRY_RUN: case WIRE_DUALOPEND_VALIDATE_LEASE: - case WIRE_DUALOPEND_LOCAL_PRIVATE_CHANNEL: case WIRE_DUALOPEND_VALIDATE_INPUTS: break; } @@ -4382,6 +4350,7 @@ int main(int argc, char *argv[]) &state->our_funding_pubkey, &state->minimum_depth, &state->require_confirmed_inputs[LOCAL], + &state->local_alias, &state->dev_accept_any_channel_type)) { /*~ Initially we're not associated with a channel, but * handle_peer_gossip_or_error compares this. */ @@ -4446,7 +4415,8 @@ int main(int argc, char *argv[]) &requested_lease, &state->channel_type, &state->require_confirmed_inputs[LOCAL], - &state->require_confirmed_inputs[REMOTE])) { + &state->require_confirmed_inputs[REMOTE], + &state->local_alias)) { bool ok; diff --git a/openingd/dualopend_wire.csv b/openingd/dualopend_wire.csv index 5efbac7865a2..01c8b70c3bf6 100644 --- a/openingd/dualopend_wire.csv +++ b/openingd/dualopend_wire.csv @@ -29,6 +29,7 @@ msgdata,dualopend_init,our_funding_pubkey,pubkey, # Constraints in case the other end tries to open a channel. msgdata,dualopend_init,minimum_depth,u32, msgdata,dualopend_init,require_confirmed_inputs,bool, +msgdata,dualopend_init,local_alias,short_channel_id, msgdata,dualopend_init,dev_accept_any_channel_type,bool, # master-dualopend: peer has reconnected @@ -77,6 +78,7 @@ msgdata,dualopend_reinit,requested_lease,?amount_sat, msgdata,dualopend_reinit,channel_type,channel_type, msgdata,dualopend_reinit,we_require_confirmed_inputs,bool, msgdata,dualopend_reinit,they_require_confirmed_inputs,bool, +msgdata,dualopend_reinit,local_alias,short_channel_id, # dualopend->master: they offered channel, should we continue? msgtype,dualopend_got_offer,7005 @@ -222,6 +224,7 @@ msgtype,dualopend_tx_sigs_sent,7012 # dualopend->peer peer locked channel msgtype,dualopend_peer_locked,7018 msgdata,dualopend_peer_locked,remote_per_commit,pubkey, +msgdata,dualopend_peer_locked,remote_alias,?short_channel_id, # dualopend->master this channel has been locked msgtype,dualopend_channel_locked,7019 @@ -279,9 +282,3 @@ msgdata,dualopend_validate_lease,their_pubkey,pubkey, msgtype,dualopend_validate_lease_reply,7127 msgdata,dualopend_validate_lease_reply,err_msg,?wirestring, - -# Tell gossipd about this (as-yet) unannounced channel -msgtype,dualopend_local_private_channel,7015 -msgdata,dualopend_local_private_channel,capacity,amount_sat, -msgdata,dualopend_local_private_channel,len,u16, -msgdata,dualopend_local_private_channel,features,u8,len diff --git a/plugins/sql.c b/plugins/sql.c index b56b454795ae..b427d876f6d3 100644 --- a/plugins/sql.c +++ b/plugins/sql.c @@ -743,7 +743,7 @@ static bool extract_scid(int gosstore_fd, size_t off, u16 type, /* For delete_chan scid immediately follows type */ if (type == WIRE_GOSSIP_STORE_DELETE_CHAN) off += 2; - else if (type == WIRE_GOSSIP_STORE_PRIVATE_UPDATE) + else if (type == WIRE_GOSSIP_STORE_PRIVATE_UPDATE_OBS) /* Prepend header */ off += 2 + 2 + update_scid_off; else if (type == WIRE_CHANNEL_UPDATE) @@ -841,7 +841,7 @@ static struct command_result *channels_refresh(struct command *cmd, /* If we see a channel_announcement, we don't care until we * see the channel_update */ if (type == WIRE_CHANNEL_UPDATE - || type == WIRE_GOSSIP_STORE_PRIVATE_UPDATE) { + || type == WIRE_GOSSIP_STORE_PRIVATE_UPDATE_OBS) { /* This can fail if entry not fully written yet. */ if (!extract_scid(gosstore_fd, off, type, &scid)) { gosstore_channels_off = off; diff --git a/tests/test_connection.py b/tests/test_connection.py index 87414c066171..8eadd6e85cf9 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -111,7 +111,7 @@ def test_remote_addr(node_factory, bitcoind): def_port = default_ln_port(l2.info["network"]) - # when we restart l1 with a channel and reconnect, node_annoucement update + # when we restart l1 with a channel and reconnect, node_announcement update # must not yet be send as we need the same `remote_addr` confirmed from a # another peer we have a channel with. # Note: In this state l2 stores remote_addr as reported by l1 @@ -125,26 +125,13 @@ def test_remote_addr(node_factory, bitcoind): assert not l2.daemon.is_in_log("Update our node_announcement for discovered address: 127.0.0.1:{}".format(def_port)) assert len(l2.rpc.getinfo()['address']) == 0 - # connect second node. This will not yet trigger `node_annoucement` update, - # as we again do not have a channel at the time we connected. - l2.rpc.connect(l3.info['id'], 'localhost', l3.port) - l2.daemon.wait_for_log("Peer says it sees our address as: 127.0.0.1:[0-9]{5}") - - # fund channel and check we didn't send Update earlier already - l2.fundchannel(l3, wait_for_active=True) - bitcoind.generate_block(5) - assert not l2.daemon.is_in_log("Update our node_announcement for discovered address: 127.0.0.1:{}".format(def_port)) - assert len(l2.rpc.getinfo()['address']) == 0 - - # restart, reconnect and re-check for updated node_annoucement. This time - # l2 sees that two different peers with channel reported the same `remote_addr`. - l3.restart() + # connect second node. This will trigger `node_announcement` update. l2.rpc.connect(l3.info['id'], 'localhost', l3.port) l2.daemon.wait_for_log("Peer says it sees our address as: 127.0.0.1:[0-9]{5}") l2.daemon.wait_for_log("Update our node_announcement for discovered address: 127.0.0.1:{}".format(def_port)) - l1.daemon.wait_for_log(f"Received node_announcement for node {l2.info['id']}") # check l1 sees the updated node announcement via CLI listnodes + l1.daemon.wait_for_log(f"Received node_announcement for node {l2.info['id']}") address = l1.rpc.listnodes(l2.info['id'])['nodes'][0]['addresses'][0] assert address['type'] == "ipv4" assert address['address'] == "127.0.0.1" @@ -159,7 +146,7 @@ def test_remote_addr(node_factory, bitcoind): def test_remote_addr_disabled(node_factory, bitcoind): - """Simply tests that IP address discovery annoucements can be turned off + """Simply tests that IP address discovery announcements can be turned off We perform logic tests on L2, setup: l1 --> [l2] <-- l3 @@ -192,7 +179,7 @@ def test_remote_addr_disabled(node_factory, bitcoind): l2.daemon.wait_for_log(f"{l3.info['id']}.*Already have funding locked in") # if ip discovery would have been enabled, we would have send an updated - # node_annoucement by now. Check we didn't... + # node_announcement by now. Check we didn't... bitcoind.generate_block(6) # ugly, but we need to wait for gossip... assert not l2.daemon.is_in_log("Update our node_announcement for discovered address") @@ -238,7 +225,7 @@ def test_remote_addr_port(node_factory, bitcoind): l2.rpc.connect(l3.info['id'], 'localhost', l3.port) # if ip discovery would have been enabled, we would have send an updated - # node_annoucement by now. Check we didn't... + # node_announcement by now. Check we didn't... l2.daemon.wait_for_logs(["Already have funding locked in", "Update our node_announcement for discovered address"]) info = l2.rpc.getinfo() @@ -971,37 +958,44 @@ def test_shutdown_reconnect(node_factory): assert l1.bitcoin.rpc.getmempoolinfo()['size'] == 1 +@unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "sqlite3-specific DB manip") def test_reconnect_remote_sends_no_sigs(node_factory): """We re-announce, even when remote node doesn't send its announcement_signatures on reconnect. """ - l1, l2 = node_factory.line_graph(2, wait_for_announce=True, opts={'may_reconnect': True}) - - # When l1 restarts (with rescan=1), make it think it hasn't - # reached announce_depth, so it wont re-send announcement_signatures - def no_blocks_above(req): - if req['params'][0] > 107: - return {"result": None, - "error": {"code": -8, "message": "Block height out of range"}, "id": req['id']} - else: - return {'result': l1.bitcoin.rpc.getblockhash(req['params'][0]), - "error": None, 'id': req['id']} + l1, l2 = node_factory.line_graph(2, wait_for_announce=True, opts={'may_reconnect': True, + 'dev-no-reconnect': None}) - l1.daemon.rpcproxy.mock_rpc('getblockhash', no_blocks_above) - l1.restart() + # Wipe l2's gossip_store + l2.stop() + gs_path = os.path.join(l2.daemon.lightning_dir, TEST_NETWORK, 'gossip_store') + os.unlink(gs_path) + l2.start() # l2 will now uses (REMOTE's) announcement_signatures it has stored - wait_for(lambda: only_one(l2.rpc.listpeerchannels()['channels'])['status'] == [ - 'CHANNELD_NORMAL:Reconnected, and reestablished.', - 'CHANNELD_NORMAL:Channel ready for use. Channel announced.']) + wait_for(lambda: l2.rpc.listchannels()['channels'] != []) + + # Remove remote signatures from l1 so it asks for them (and delete gossip store) + l1.db_manip("UPDATE channels SET remote_ann_node_sig=NULL, remote_ann_bitcoin_sig=NULL") + gs_path = os.path.join(l1.daemon.lightning_dir, TEST_NETWORK, 'gossip_store') + os.unlink(gs_path) + l1.restart() + + l1.connect(l2) + l1needle = l1.daemon.logsearch_start + l2needle = l2.daemon.logsearch_start + + # l1 asks once, l2 replies once. + # Make sure we get all the msgs! + time.sleep(5) - # But l2 still sends its own sigs on reconnect - l2.daemon.wait_for_logs([r'peer_out WIRE_ANNOUNCEMENT_SIGNATURES', - r'peer_out WIRE_ANNOUNCEMENT_SIGNATURES']) + l1.daemon.wait_for_log('peer_out WIRE_ANNOUNCEMENT_SIGNATURES') + l2.daemon.wait_for_log('peer_out WIRE_ANNOUNCEMENT_SIGNATURES') - count = ''.join(l1.daemon.logs).count(r'peer_out WIRE_ANNOUNCEMENT_SIGNATURES') + l1msgs = [l.split()[4] for l in l1.daemon.logs[l1needle:] if 'WIRE_ANNOUNCEMENT_SIGNATURES' in l] + assert l1msgs == ['peer_out', 'peer_in'] - # l1 only did send them the first time - assert(count == 1 or count == 2) + # l2 only sends one. + assert len([l for l in l2.daemon.logs[l2needle:] if 'peer_out WIRE_ANNOUNCEMENT_SIGNATURES' in l]) == 1 @pytest.mark.openchannel('v1') @@ -1863,7 +1857,7 @@ def test_multifunding_v2_exclusive(node_factory, bitcoind): "amount": 50000}] l1.rpc.multifundchannel(destinations) - bitcoind.generate_block(6, wait_for_mempool=1) + mine_funding_to_announce(bitcoind, [l1, l2, l3], num_blocks=6, wait_for_mempool=1) for node in [l1, l2, l3, l4]: node.daemon.wait_for_log(r'to CHANNELD_NORMAL') @@ -1897,7 +1891,10 @@ def test_multifunding_simple(node_factory, bitcoind): "amount": 50000}] l1.rpc.multifundchannel(destinations) - bitcoind.generate_block(6, wait_for_mempool=1) + bitcoind.generate_block(1, wait_for_mempool=1) + # Don't have others reject channel_announcement as too far in future. + sync_blockheight(bitcoind, [l1, l2, l3, l4]) + bitcoind.generate_block(5) for node in [l1, l2, l3, l4]: node.daemon.wait_for_log(r'to CHANNELD_NORMAL') @@ -3477,6 +3474,8 @@ def test_wumbo_channels(node_factory, bitcoind): # Get that mined, and announced. bitcoind.generate_block(6, wait_for_mempool=1) + # Make sure l3 is ready to receive channel announcement! + sync_blockheight(bitcoind, [l1, l2, l3]) # Connect l3, get gossip. l3.rpc.connect(l1.info['id'], 'localhost', port=l1.port) @@ -3527,9 +3526,6 @@ def test_wumbo_channels(node_factory, bitcoind): # And we can wumbo pay, right? inv = l2.rpc.invoice(str(1 << 24) + "sat", "test_wumbo_channels", "wumbo payment") - # We actually do warn about capacity: l2 sees that *l1* doesn't have - # enough incoming to pay (not knowing that l1 is the intended payer). - assert 'warning_capacity' in inv assert 'warning_mpp' not in inv l1.rpc.pay(inv['bolt11']) @@ -4027,7 +4023,7 @@ def test_multichan_stress(node_factory, executor, bitcoind): assert(len(l3.rpc.listpeerchannels(l2.info['id'])['channels']) == 2) # Make sure gossip works. - bitcoind.generate_block(6, wait_for_mempool=1) + mine_funding_to_announce(bitcoind, [l1, l2, l3], num_blocks=6, wait_for_mempool=1) wait_for(lambda: len(l1.rpc.listchannels(source=l3.info['id'])['channels']) == 2) def send_many_payments(): @@ -4465,3 +4461,34 @@ def test_offline_fd_check(node_factory): # if get_node starts it, it'll expect an address, so do it manually. l1 = node_factory.get_node(options={"offline": None}, start=False) l1.daemon.start() + + +def test_last_stable_connection(node_factory): + l1, l2 = node_factory.line_graph(2, opts={'may_reconnect': True}) + + # We wait a minute to be stable. + STABLE_TIME = 60 + assert 'last_stable_connection' not in only_one(l1.rpc.listpeerchannels()['channels']) + assert 'last_stable_connection' not in only_one(l2.rpc.listpeerchannels()['channels']) + + recon_time = time.time() + + # This take a minute, so don't fail if TIMEOUT is set to 10. + wait_for(lambda: 'last_stable_connection' in only_one(l1.rpc.listpeerchannels()['channels']), timeout=STABLE_TIME + 15) + l1stable = only_one(l1.rpc.listpeerchannels()['channels'])['last_stable_connection'] + wait_for(lambda: 'last_stable_connection' in only_one(l2.rpc.listpeerchannels()['channels'])) + l2stable = only_one(l2.rpc.listpeerchannels()['channels'])['last_stable_connection'] + + # Disconnect, and/or restart then reconnect. + l1.rpc.disconnect(l2.info['id'], force=True) + recon_time = time.time() + l2.restart() + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + + assert only_one(l1.rpc.listpeerchannels()['channels'])['last_stable_connection'] == l1stable + assert only_one(l2.rpc.listpeerchannels()['channels'])['last_stable_connection'] == l2stable + wait_for(lambda: only_one(l1.rpc.listpeerchannels()['channels'])['last_stable_connection'] != l1stable, timeout=STABLE_TIME + 15) + wait_for(lambda: only_one(l2.rpc.listpeerchannels()['channels'])['last_stable_connection'] != l2stable) + + assert only_one(l1.rpc.listpeerchannels()['channels'])['last_stable_connection'] > recon_time + STABLE_TIME + assert only_one(l2.rpc.listpeerchannels()['channels'])['last_stable_connection'] > recon_time + STABLE_TIME diff --git a/tests/test_gossip.py b/tests/test_gossip.py index 52ae05f99c17..bcf5c488e41e 100644 --- a/tests/test_gossip.py +++ b/tests/test_gossip.py @@ -15,7 +15,6 @@ import math import os import pytest -import re import struct import subprocess import time @@ -179,7 +178,7 @@ def test_announce_dns_suppressed(node_factory, bitcoind): def test_announce_and_connect_via_dns(node_factory, bitcoind): - """ Test that DNS annoucements propagate and can be used when connecting. + """ Test that DNS announcements propagate and can be used when connecting. - First node announces only a FQDN like 'localhost.localdomain'. - Second node gets a channel with first node. @@ -270,8 +269,6 @@ def test_announce_dns_without_port(node_factory, bitcoind): def test_gossip_timestamp_filter(node_factory, bitcoind, chainparams): - # Updates get backdated 5 seconds with --dev-fast-gossip. - backdate = 5 l1, l2, l3, l4 = node_factory.line_graph(4, fundchannel=False, opts={'log-level': 'io'}) genesis_blockhash = chainparams['chain_hash'] @@ -311,14 +308,14 @@ def test_gossip_timestamp_filter(node_factory, bitcoind, chainparams): # Now timestamp which doesn't overlap (gives nothing). msgs = l4.query_gossip('gossip_timestamp_filter', genesis_blockhash, - '0', before_anything - backdate, + '0', before_anything, filters=['0109', '0107', '0012']) assert msgs == [] # Now choose range which will only give first update. msgs = l4.query_gossip('gossip_timestamp_filter', genesis_blockhash, - before_anything - backdate, + before_anything, after_12 - before_anything + 1, filters=['0109', '0107', '0012']) @@ -332,7 +329,7 @@ def test_gossip_timestamp_filter(node_factory, bitcoind, chainparams): # Now choose range which will only give second update. msgs = l4.query_gossip('gossip_timestamp_filter', genesis_blockhash, - before_23 - backdate, + before_23, after_23 - before_23 + 1, filters=['0109', '0107', '0012']) @@ -602,7 +599,7 @@ def non_public(node): wait_for(lambda: non_public(l4) == [scid34]) -def test_routing_gossip_reconnect(node_factory): +def test_routing_gossip_reconnect(node_factory, bitcoind): # Connect two peers, reconnect and then see if we resume the # gossip. disconnects = ['-WIRE_CHANNEL_ANNOUNCEMENT'] @@ -611,9 +608,15 @@ def test_routing_gossip_reconnect(node_factory): 'may_reconnect': True}, {'may_reconnect': True}, {}]) + # Make sure everyone is up to block height so we don't get bad gossip msgs! + sync_blockheight(bitcoind, [l1, l2, l3]) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) l1.openchannel(l2, CHANNEL_SIZE) + # Make sure everyone is up to block height so we don't get bad gossip msgs! + sync_blockheight(bitcoind, [l1, l2, l3]) + # Now open new channels and everybody should sync l2.rpc.connect(l3.info['id'], 'localhost', l3.port) l2.openchannel(l3, CHANNEL_SIZE) @@ -1070,10 +1073,6 @@ def test_gossip_lease_rates(node_factory, bitcoind): '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 @@ -1093,6 +1092,8 @@ def test_gossip_lease_rates(node_factory, bitcoind): l1.rpc.connect(l2.info['id'], 'localhost', l2.port) l1.fundchannel(l2, 10**6) + # Don't have l2 reject channel_announcement as too far in future. + sync_blockheight(bitcoind, [l1, l2]) # Announce depth is ALWAYS 6 blocks bitcoind.generate_block(5) @@ -1627,7 +1628,7 @@ def test_gossip_store_load_no_channel_update(node_factory): # A channel announcement with no channel_update. with open(os.path.join(l1.daemon.lightning_dir, TEST_NETWORK, 'gossip_store'), 'wb') as f: - f.write(bytearray.fromhex("0c" # GOSSIP_STORE_VERSION + f.write(bytearray.fromhex("0d" # GOSSIP_STORE_VERSION "000001b0" # len "fea676e8" # csum "5b8d9b44" # timestamp @@ -1654,7 +1655,7 @@ def test_gossip_store_load_no_channel_update(node_factory): l1.rpc.call('dev-compact-gossip-store') with open(os.path.join(l1.daemon.lightning_dir, TEST_NETWORK, 'gossip_store'), "rb") as f: - assert bytearray(f.read()) == bytearray.fromhex("0c") + assert bytearray(f.read()) == bytearray.fromhex("0d") def test_gossip_store_compact_on_load(node_factory, bitcoind): @@ -1668,15 +1669,9 @@ def test_gossip_store_compact_on_load(node_factory, bitcoind): l2.restart() # These appear before we're fully started, so will already in log: - # FIXME: this will change! - line = l2.daemon.is_in_log(r'gossip_store_compact_offline: .* deleted, .* copied') - m = re.search(r'gossip_store_compact_offline: (.*) deleted', line) - # We can have private re-tranmissions, but at minumum we had a deleted private - # channel message and two private updates, then two deleted updates. - assert int(m.group(1)) >= 5 - - # FIXME: this will change! - assert l2.daemon.is_in_log(r'gossip_store: Read 2/4/[23]/0 cannounce/cupdate/nannounce/cdelete from store \(0 deleted\) in [0-9]* bytes') + l2.daemon.is_in_log(r'gossip_store_compact_offline: 2 deleted, 9 copied') + + assert l2.daemon.is_in_log(r'gossip_store: Read 2/4/3/0 cannounce/cupdate/nannounce/cdelete from store \(0 deleted\) in 2016 bytes') def test_gossip_announce_invalid_block(node_factory, bitcoind): diff --git a/tests/test_misc.py b/tests/test_misc.py index eda55d0464d5..09410cd6a146 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -1311,7 +1311,8 @@ def no_more_blocks(req): bitcoind.generate_block(1) l1.daemon.wait_for_log(r'Short channel id changed from 103x1x0->104x1x0') - l2.daemon.wait_for_logs([r'Peer transient failure in CHANNELD_NORMAL: channeld sent Bad node_signature*']) + # We are OK with this! + l2.daemon.wait_for_log(r'channel_gossip: received announcement sigs for 104x1x0 \(we have 103x1x0\)') # Unblinding l2 brings it back in sync, restarts channeld and sends its announce sig l2.daemon.rpcproxy.mock_rpc('getblockhash', None) @@ -2794,7 +2795,8 @@ def test_restorefrompeer(node_factory, bitcoind): """ l1, l2 = node_factory.get_nodes(2, [{'allow_broken_log': True, 'experimental-peer-storage': None, - 'may_reconnect': True}, + 'may_reconnect': True, + 'allow_bad_gossip': True}, {'experimental-peer-storage': None, 'may_reconnect': True}]) diff --git a/tests/test_opening.py b/tests/test_opening.py index 78f38d304847..d0f9b83116de 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -1724,10 +1724,9 @@ def test_zeroconf_public(bitcoind, node_factory, chainparams): l1.connect(l2) l1.rpc.fundchannel(l2.info['id'], 'all', mindepth=0, push_msat=push_msat) - # Wait for the update to be signed (might not be the most reliable - # signal) - l1.daemon.wait_for_log(r'Got WIRE_HSMD_CUPDATE_SIG_REQ') - l2.daemon.wait_for_log(r'Got WIRE_HSMD_CUPDATE_SIG_REQ') + # Wait for the alias to be sent to peer. + wait_for(lambda: 'remote' in only_one(l1.rpc.listpeerchannels()['channels'])['updates']) + wait_for(lambda: 'remote' in only_one(l2.rpc.listpeerchannels()['channels'])['updates']) l1chan = only_one(l1.rpc.listpeerchannels()['channels']) l2chan = only_one(l2.rpc.listpeerchannels()['channels']) diff --git a/tests/test_pay.py b/tests/test_pay.py index 28bf7c5efb37..ad157ce442b5 100644 --- a/tests/test_pay.py +++ b/tests/test_pay.py @@ -310,6 +310,10 @@ def test_pay_get_error_with_update(node_factory): wait_for(lambda: only_one(l2.rpc.listpeerchannels(l3.info['id'])['channels'])['peer_connected'] is False) assert(l1.is_channel_active(chanid2)) + + # Make sure it's not doing startup any more (where it doesn't disable channels!) + l1.daemon.wait_for_log("channel_gossip: no longer in startup mode", timeout=70) + with pytest.raises(RpcError, match=r'WIRE_TEMPORARY_CHANNEL_FAILURE'): l1.rpc.pay(inv['bolt11']) diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 0d341e64ee2b..f9c77fe70bf6 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -3506,7 +3506,9 @@ def test_sql(node_factory, bitcoind): {'name': 'last_commitment_fee_msat', 'type': 'msat'}, {'name': 'close_cause', - 'type': 'string'}]}, + 'type': 'string'}, + {'name': 'last_stable_connection', + 'type': 'u64'}]}, 'closedchannels_channel_type_bits': { 'columns': [{'name': 'row', 'type': 'u64'}, @@ -3840,6 +3842,10 @@ def test_sql(node_factory, bitcoind): 'type': 'u64'}, {'name': 'out_fulfilled_msat', 'type': 'msat'}, + {'name': 'last_stable_connection', + 'type': 'u64'}, + {'name': 'reestablished', + 'type': 'boolean'}, {'name': 'close_to_addr', 'type': 'string'}, {'name': 'last_tx_fee_msat', diff --git a/tests/test_splicing.py b/tests/test_splicing.py index 87a3cf4994a8..019eaaf29b72 100644 --- a/tests/test_splicing.py +++ b/tests/test_splicing.py @@ -5,7 +5,7 @@ import unittest import time from utils import ( - wait_for, TEST_NETWORK, first_scid, only_one + sync_blockheight, wait_for, TEST_NETWORK, first_scid, only_one ) @@ -313,7 +313,10 @@ def test_splice_stuck_htlc(node_factory, bitcoind, executor): assert len(list(mempool.keys())) == 1 assert result['txid'] in list(mempool.keys()) - bitcoind.generate_block(6, wait_for_mempool=1) + bitcoind.generate_block(1, wait_for_mempool=1) + # Don't have l2, l3 reject channel_announcement as too far in future. + sync_blockheight(bitcoind, [l1, l2, l3]) + bitcoind.generate_block(5) l2.daemon.wait_for_log(r'CHANNELD_AWAITING_SPLICE to CHANNELD_NORMAL') l1.daemon.wait_for_log(r'CHANNELD_AWAITING_SPLICE to CHANNELD_NORMAL') diff --git a/wallet/db.c b/wallet/db.c index 3215f86cdea4..53b83481b67e 100644 --- a/wallet/db.c +++ b/wallet/db.c @@ -1016,6 +1016,7 @@ static struct migration dbmigrations[] = { {SQL("ALTER TABLE channels ADD remote_cltv_expiry_delta INTEGER DEFAULT NULL;"), NULL}, {SQL("ALTER TABLE channels ADD remote_htlc_maximum_msat BIGINT DEFAULT NULL;"), NULL}, {SQL("ALTER TABLE channels ADD remote_htlc_minimum_msat BIGINT DEFAULT NULL;"), NULL}, + {SQL("ALTER TABLE channels ADD last_stable_connection BIGINT DEFAULT 0;"), NULL}, }; /** diff --git a/wallet/test/run-db.c b/wallet/test/run-db.c index bb6afec36ac5..50fa0e6917a8 100644 --- a/wallet/test/run-db.c +++ b/wallet/test/run-db.c @@ -25,6 +25,12 @@ static void db_log_(struct logger *log UNUSED, enum log_level level UNUSED, cons /* Generated stub for bip32_pubkey */ void bip32_pubkey(struct lightningd *ld UNNEEDED, struct pubkey *pubkey UNNEEDED, u32 index UNNEEDED) { fprintf(stderr, "bip32_pubkey called!\n"); abort(); } +/* Generated stub for channel_gossip_get_remote_update */ +const struct peer_update *channel_gossip_get_remote_update(const struct channel *channel UNNEEDED) +{ fprintf(stderr, "channel_gossip_get_remote_update called!\n"); abort(); } +/* Generated stub for channel_gossip_update */ +void channel_gossip_update(struct channel *channel UNNEEDED) +{ fprintf(stderr, "channel_gossip_update called!\n"); abort(); } /* Generated stub for channel_scid_or_local_alias */ const struct short_channel_id *channel_scid_or_local_alias(const struct channel *chan UNNEEDED) { fprintf(stderr, "channel_scid_or_local_alias called!\n"); abort(); } @@ -178,7 +184,8 @@ struct channel *new_channel(struct peer *peer UNNEEDED, u64 dbid UNNEEDED, struct amount_msat htlc_maximum_msat UNNEEDED, bool ignore_fee_limits UNNEEDED, /* NULL or stolen */ - struct peer_update *peer_update STEALS UNNEEDED) + struct peer_update *peer_update STEALS UNNEEDED, + u64 last_stable_connection UNNEEDED) { fprintf(stderr, "new_channel called!\n"); abort(); } /* Generated stub for new_coin_wallet_deposit */ struct chain_coin_mvt *new_coin_wallet_deposit(const tal_t *ctx UNNEEDED, diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 1ef36ffb6705..04160f03b1c9 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -26,6 +26,7 @@ static void test_error(struct lightningd *ld, bool fatal, const char *fmt, va_li #include "lightningd/peer_control.c" #include "lightningd/peer_htlcs.c" #include "lightningd/channel.c" +#include "lightningd/channel_gossip.c" #include "lightningd/pay.c" #include "lightningd/wait.c" @@ -40,6 +41,10 @@ static void test_error(struct lightningd *ld, bool fatal, const char *fmt, va_li #include /* AUTOGENERATED MOCKS START */ +/* Generated stub for add_node_announcement_sig */ +void add_node_announcement_sig(u8 *nannounce UNNEEDED, + const secp256k1_ecdsa_signature *sig UNNEEDED) +{ fprintf(stderr, "add_node_announcement_sig called!\n"); abort(); } /* Generated stub for bigsize_put */ size_t bigsize_put(u8 buf[BIGSIZE_MAX_LEN] UNNEEDED, bigsize_t v UNNEEDED) { fprintf(stderr, "bigsize_put called!\n"); abort(); } @@ -85,6 +90,11 @@ void broadcast_tx_(const tal_t *ctx UNNEEDED, /* Generated stub for channel_unsaved_close_conn */ void channel_unsaved_close_conn(struct channel *channel UNNEEDED, const char *why UNNEEDED) { fprintf(stderr, "channel_unsaved_close_conn called!\n"); abort(); } +/* Generated stub for channel_update_details */ +bool channel_update_details(const u8 *channel_update UNNEEDED, + u32 *timestamp UNNEEDED, + bool *enabled UNNEEDED) +{ fprintf(stderr, "channel_update_details called!\n"); abort(); } /* Generated stub for channel_update_feerates */ void channel_update_feerates(struct lightningd *ld UNNEEDED, const struct channel *channel UNNEEDED) { fprintf(stderr, "channel_update_feerates called!\n"); abort(); } @@ -93,11 +103,20 @@ void channel_update_reserve(struct channel *channel UNNEEDED, struct channel_config *their_config UNNEEDED, struct amount_sat funding_total UNNEEDED) { fprintf(stderr, "channel_update_reserve called!\n"); abort(); } +/* Generated stub for channel_update_same */ +bool channel_update_same(const u8 *cupdate1 UNNEEDED, const u8 *cupdate2 UNNEEDED) +{ fprintf(stderr, "channel_update_same called!\n"); abort(); } /* Generated stub for channeld_tell_depth */ void channeld_tell_depth(struct channel *channel UNNEEDED, const struct bitcoin_txid *txid UNNEEDED, u32 depth UNNEEDED) { fprintf(stderr, "channeld_tell_depth called!\n"); abort(); } +/* Generated stub for check_announce_sigs */ +const char *check_announce_sigs(const struct channel *channel UNNEEDED, + struct short_channel_id scid UNNEEDED, + const secp256k1_ecdsa_signature *remote_node_signature UNNEEDED, + const secp256k1_ecdsa_signature *remote_bitcoin_signature UNNEEDED) +{ fprintf(stderr, "check_announce_sigs called!\n"); abort(); } /* Generated stub for cmd_id_from_close_command */ const char *cmd_id_from_close_command(const tal_t *ctx UNNEEDED, struct lightningd *ld UNNEEDED, struct channel *channel UNNEEDED) @@ -162,6 +181,15 @@ struct anchor_details *create_anchor_details(const tal_t *ctx UNNEEDED, struct channel *channel UNNEEDED, const struct bitcoin_tx *tx UNNEEDED) { fprintf(stderr, "create_anchor_details called!\n"); abort(); } +/* Generated stub for create_channel_announcement */ +u8 *create_channel_announcement(const tal_t *ctx UNNEEDED, + const struct channel *channel UNNEEDED, + struct short_channel_id scid UNNEEDED, + const secp256k1_ecdsa_signature *local_node_signature UNNEEDED, + const secp256k1_ecdsa_signature *local_bitcoin_signature UNNEEDED, + const secp256k1_ecdsa_signature *remote_node_signature UNNEEDED, + const secp256k1_ecdsa_signature *remote_bitcoin_signature UNNEEDED) +{ fprintf(stderr, "create_channel_announcement called!\n"); abort(); } /* Generated stub for create_onionpacket */ struct onionpacket *create_onionpacket( const tal_t * ctx UNNEEDED, @@ -257,12 +285,18 @@ bool fromwire_connectd_peer_spoke(const tal_t *ctx UNNEEDED, const void *p UNNEE /* Generated stub for fromwire_dualopend_dev_memleak_reply */ bool fromwire_dualopend_dev_memleak_reply(const void *p UNNEEDED, bool *leak UNNEEDED) { fprintf(stderr, "fromwire_dualopend_dev_memleak_reply called!\n"); abort(); } +/* Generated stub for fromwire_gossipd_addgossip_reply */ +bool fromwire_gossipd_addgossip_reply(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, wirestring **err UNNEEDED) +{ fprintf(stderr, "fromwire_gossipd_addgossip_reply called!\n"); abort(); } /* Generated stub for fromwire_hsmd_check_pubkey_reply */ bool fromwire_hsmd_check_pubkey_reply(const void *p UNNEEDED, bool *ok UNNEEDED) { fprintf(stderr, "fromwire_hsmd_check_pubkey_reply called!\n"); abort(); } /* Generated stub for fromwire_hsmd_client_hsmfd_reply */ bool fromwire_hsmd_client_hsmfd_reply(const void *p UNNEEDED) { fprintf(stderr, "fromwire_hsmd_client_hsmfd_reply 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_derive_secret_reply */ bool fromwire_hsmd_derive_secret_reply(const void *p UNNEEDED, struct secret *secret UNNEEDED) { fprintf(stderr, "fromwire_hsmd_derive_secret_reply called!\n"); abort(); } @@ -281,6 +315,12 @@ bool fromwire_hsmd_init_reply_v4(const tal_t *ctx UNNEEDED, const void *p UNNEED /* Generated stub for fromwire_hsmd_new_channel_reply */ bool fromwire_hsmd_new_channel_reply(const void *p UNNEEDED) { fprintf(stderr, "fromwire_hsmd_new_channel_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 fromwire_hsmd_sign_any_cannouncement_reply */ +bool fromwire_hsmd_sign_any_cannouncement_reply(const void *p UNNEEDED, secp256k1_ecdsa_signature *node_signature UNNEEDED, secp256k1_ecdsa_signature *bitcoin_signature UNNEEDED) +{ fprintf(stderr, "fromwire_hsmd_sign_any_cannouncement_reply called!\n"); abort(); } /* Generated stub for fromwire_hsmd_sign_commitment_tx_reply */ bool fromwire_hsmd_sign_commitment_tx_reply(const void *p UNNEEDED, struct bitcoin_signature *sig UNNEEDED) { fprintf(stderr, "fromwire_hsmd_sign_commitment_tx_reply called!\n"); abort(); } @@ -296,9 +336,6 @@ bool fromwire_openingd_dev_memleak_reply(const void *p UNNEEDED, bool *leak UNNE /* Generated stub for get_block_height */ u32 get_block_height(const struct chain_topology *topo UNNEEDED) { fprintf(stderr, "get_block_height called!\n"); abort(); } -/* Generated stub for get_channel_update */ -const u8 *get_channel_update(struct channel *channel UNNEEDED) -{ fprintf(stderr, "get_channel_update called!\n"); abort(); } /* Generated stub for hsmd_wire_name */ const char *hsmd_wire_name(int e UNNEEDED) { fprintf(stderr, "hsmd_wire_name called!\n"); abort(); } @@ -628,6 +665,9 @@ struct peer_fd *new_peer_fd(const tal_t *ctx UNNEEDED, int peer_fd UNNEEDED) /* Generated stub for new_uncommitted_channel */ struct uncommitted_channel *new_uncommitted_channel(struct peer *peer UNNEEDED) { fprintf(stderr, "new_uncommitted_channel called!\n"); abort(); } +/* Generated stub for node_announcement_same */ +bool node_announcement_same(const u8 *nann1 UNNEEDED, const u8 *nann2 UNNEEDED) +{ fprintf(stderr, "node_announcement_same called!\n"); abort(); } /* Generated stub for notify_chain_mvt */ void notify_chain_mvt(struct lightningd *ld UNNEEDED, const struct chain_coin_mvt *mvt UNNEEDED) { fprintf(stderr, "notify_chain_mvt called!\n"); abort(); } @@ -953,11 +993,6 @@ void subkey_from_hmac(const char *prefix UNNEEDED, const struct secret *base UNNEEDED, struct secret *key UNNEEDED) { fprintf(stderr, "subkey_from_hmac called!\n"); abort(); } -/* Generated stub for tell_gossipd_local_channel_update */ -void tell_gossipd_local_channel_update(struct lightningd *ld UNNEEDED, - struct channel *channel UNNEEDED, - bool enabled UNNEEDED) -{ fprintf(stderr, "tell_gossipd_local_channel_update called!\n"); abort(); } /* Generated stub for to_canonical_invstr */ const char *to_canonical_invstr(const tal_t *ctx UNNEEDED, const char *invstring UNNEEDED) { fprintf(stderr, "to_canonical_invstr called!\n"); abort(); } @@ -968,6 +1003,9 @@ void topology_add_sync_waiter_(const tal_t *ctx UNNEEDED, void *) UNNEEDED, void *arg UNNEEDED) { fprintf(stderr, "topology_add_sync_waiter_ called!\n"); abort(); } +/* Generated stub for towire_announcement_signatures */ +u8 *towire_announcement_signatures(const tal_t *ctx UNNEEDED, const struct channel_id *channel_id UNNEEDED, const struct short_channel_id *short_channel_id UNNEEDED, const secp256k1_ecdsa_signature *node_signature UNNEEDED, const secp256k1_ecdsa_signature *bitcoin_signature UNNEEDED) +{ fprintf(stderr, "towire_announcement_signatures called!\n"); abort(); } /* Generated stub for towire_channeld_dev_memleak */ u8 *towire_channeld_dev_memleak(const tal_t *ctx UNNEEDED) { fprintf(stderr, "towire_channeld_dev_memleak called!\n"); abort(); } @@ -992,12 +1030,15 @@ u8 *towire_channeld_offer_htlc(const tal_t *ctx UNNEEDED, struct amount_msat amo /* Generated stub for towire_channeld_sending_commitsig_reply */ u8 *towire_channeld_sending_commitsig_reply(const tal_t *ctx UNNEEDED) { fprintf(stderr, "towire_channeld_sending_commitsig_reply called!\n"); abort(); } +/* Generated stub for towire_connectd_discard_peer */ +u8 *towire_connectd_discard_peer(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, u64 counter UNNEEDED) +{ fprintf(stderr, "towire_connectd_discard_peer called!\n"); abort(); } /* Generated stub for towire_connectd_peer_connect_subd */ u8 *towire_connectd_peer_connect_subd(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, u64 counter UNNEEDED, const struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "towire_connectd_peer_connect_subd called!\n"); abort(); } -/* Generated stub for towire_connectd_peer_final_msg */ -u8 *towire_connectd_peer_final_msg(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, u64 counter UNNEEDED, const u8 *msg UNNEEDED) -{ fprintf(stderr, "towire_connectd_peer_final_msg called!\n"); abort(); } +/* Generated stub for towire_connectd_peer_send_msg */ +u8 *towire_connectd_peer_send_msg(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, u64 counter UNNEEDED, const u8 *msg UNNEEDED) +{ fprintf(stderr, "towire_connectd_peer_send_msg called!\n"); abort(); } /* Generated stub for towire_dualopend_dev_memleak */ u8 *towire_dualopend_dev_memleak(const tal_t *ctx UNNEEDED) { fprintf(stderr, "towire_dualopend_dev_memleak called!\n"); abort(); } @@ -1021,15 +1062,18 @@ u8 *towire_final_incorrect_cltv_expiry(const tal_t *ctx UNNEEDED, u32 cltv_expir /* Generated stub for towire_final_incorrect_htlc_amount */ u8 *towire_final_incorrect_htlc_amount(const tal_t *ctx UNNEEDED, struct amount_msat incoming_htlc_amt UNNEEDED) { fprintf(stderr, "towire_final_incorrect_htlc_amount called!\n"); abort(); } -/* Generated stub for towire_gossipd_discovered_ip */ -u8 *towire_gossipd_discovered_ip(const tal_t *ctx UNNEEDED, const struct wireaddr *discovered_ip UNNEEDED) -{ fprintf(stderr, "towire_gossipd_discovered_ip called!\n"); abort(); } +/* Generated stub for towire_gossipd_addgossip */ +u8 *towire_gossipd_addgossip(const tal_t *ctx UNNEEDED, const u8 *msg UNNEEDED) +{ fprintf(stderr, "towire_gossipd_addgossip called!\n"); abort(); } /* Generated stub for towire_hsmd_check_pubkey */ u8 *towire_hsmd_check_pubkey(const tal_t *ctx UNNEEDED, u32 index UNNEEDED, const struct pubkey *pubkey UNNEEDED) { fprintf(stderr, "towire_hsmd_check_pubkey called!\n"); abort(); } /* Generated stub for towire_hsmd_client_hsmfd */ u8 *towire_hsmd_client_hsmfd(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, u64 dbid UNNEEDED, u64 permissions UNNEEDED) { fprintf(stderr, "towire_hsmd_client_hsmfd 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_derive_secret */ u8 *towire_hsmd_derive_secret(const tal_t *ctx UNNEEDED, const u8 *info UNNEEDED) { fprintf(stderr, "towire_hsmd_derive_secret called!\n"); abort(); } @@ -1045,6 +1089,12 @@ u8 *towire_hsmd_init(const tal_t *ctx UNNEEDED, const struct bip32_key_version * /* Generated stub for towire_hsmd_new_channel */ u8 *towire_hsmd_new_channel(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, u64 dbid UNNEEDED) { fprintf(stderr, "towire_hsmd_new_channel 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_hsmd_sign_any_cannouncement_req */ +u8 *towire_hsmd_sign_any_cannouncement_req(const tal_t *ctx UNNEEDED, const u8 *ca UNNEEDED, const struct node_id *peerid UNNEEDED, u64 channel_dbid UNNEEDED) +{ fprintf(stderr, "towire_hsmd_sign_any_cannouncement_req called!\n"); abort(); } /* Generated stub for towire_hsmd_sign_commitment_tx */ u8 *towire_hsmd_sign_commitment_tx(const tal_t *ctx UNNEEDED, const struct node_id *peer_id UNNEEDED, u64 channel_dbid UNNEEDED, const struct bitcoin_tx *tx UNNEEDED, const struct pubkey *remote_funding_key UNNEEDED, u64 commit_num UNNEEDED) { fprintf(stderr, "towire_hsmd_sign_commitment_tx called!\n"); abort(); } @@ -1112,6 +1162,19 @@ void try_reconnect(const tal_t *ctx UNNEEDED, struct peer *peer UNNEEDED, const struct wireaddr_internal *addrhint UNNEEDED) { fprintf(stderr, "try_reconnect called!\n"); abort(); } +/* Generated stub for unsigned_channel_update */ +u8 *unsigned_channel_update(const tal_t *ctx UNNEEDED, + const struct channel *channel UNNEEDED, + const struct short_channel_id *scid UNNEEDED, + const u32 *old_timestamp UNNEEDED, + bool forwardable UNNEEDED, + bool enabled UNNEEDED) +{ fprintf(stderr, "unsigned_channel_update called!\n"); abort(); } +/* Generated stub for unsigned_node_announcement */ +u8 *unsigned_node_announcement(const tal_t *ctx UNNEEDED, + struct lightningd *ld UNNEEDED, + const u8 *prev UNNEEDED) +{ fprintf(stderr, "unsigned_node_announcement called!\n"); abort(); } /* Generated stub for unwrap_onionreply */ u8 *unwrap_onionreply(const tal_t *ctx UNNEEDED, const struct secret *shared_secrets UNNEEDED, @@ -1814,12 +1877,16 @@ static bool test_channel_crud(struct lightningd *ld, const tal_t *ctx) wallet_announcement_save(w, c1.dbid, node_sig1, bitcoin_sig1); CHECK_MSG(!wallet_err, tal_fmt(w, "Insert ann sigs into DB: %s", wallet_err)); - CHECK_MSG(load = wallet_remote_ann_sigs_load(w, w, c1.dbid, &node_sig2, &bitcoin_sig2), tal_fmt(w, "Load ann sigs from DB")); + node_sig2 = tal(tmpctx, secp256k1_ecdsa_signature); + bitcoin_sig2 = tal(tmpctx, secp256k1_ecdsa_signature); + CHECK_MSG(load = wallet_remote_ann_sigs_load(w, &c1, node_sig2, bitcoin_sig2), tal_fmt(w, "Load ann sigs from DB")); CHECK_MSG(!wallet_err, tal_fmt(w, "Load ann sigs from DB: %s", wallet_err)); CHECK(load == true); CHECK_MSG(!memcmp(node_sig1, node_sig2, sizeof(*node_sig1)), "Compare ann sigs loaded with saved (v5)"); CHECK_MSG(!memcmp(bitcoin_sig1, bitcoin_sig2, sizeof(*node_sig1)), "Compare ann sigs loaded with saved (v5)"); + wallet_remote_ann_sigs_clear(w, &c1); + CHECK(!wallet_remote_ann_sigs_load(w, &c1, node_sig2, bitcoin_sig2)); db_commit_transaction(w->db); CHECK(!wallet_err); @@ -1942,7 +2009,8 @@ static bool test_channel_inflight_crud(struct lightningd *ld, const tal_t *ctx) AMOUNT_MSAT(0), AMOUNT_MSAT(-1ULL), false, - NULL); + NULL, + 0); db_begin_transaction(w->db); CHECK(!wallet_err); wallet_channel_insert(w, chan); diff --git a/wallet/wallet.c b/wallet/wallet.c index f7af8fea48fd..da9d789c86dc 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -1075,16 +1076,17 @@ wallet_htlc_sigs_load(const tal_t *ctx, struct wallet *w, u64 channelid, return htlc_sigs; } -bool wallet_remote_ann_sigs_load(const tal_t *ctx, struct wallet *w, u64 id, - secp256k1_ecdsa_signature **remote_ann_node_sig, - secp256k1_ecdsa_signature **remote_ann_bitcoin_sig) +bool wallet_remote_ann_sigs_load(struct wallet *w, + const struct channel *chan, + secp256k1_ecdsa_signature *remote_ann_node_sig, + secp256k1_ecdsa_signature *remote_ann_bitcoin_sig) { struct db_stmt *stmt; bool res; stmt = db_prepare_v2( w->db, SQL("SELECT remote_ann_node_sig, remote_ann_bitcoin_sig" " FROM channels WHERE id = ?")); - db_bind_u64(stmt, id); + db_bind_u64(stmt, chan->dbid); db_query_prepared(stmt); res = db_step(stmt); @@ -1096,29 +1098,31 @@ bool wallet_remote_ann_sigs_load(const tal_t *ctx, struct wallet *w, u64 id, if (db_col_is_null(stmt, "remote_ann_node_sig") || db_col_is_null(stmt, "remote_ann_bitcoin_sig")) { db_col_ignore(stmt, "remote_ann_bitcoin_sig"); - *remote_ann_node_sig = *remote_ann_bitcoin_sig = NULL; tal_free(stmt); - return true; + return false; } - /* the case left over is both sigs exist */ - *remote_ann_node_sig = tal(ctx, secp256k1_ecdsa_signature); - *remote_ann_bitcoin_sig = tal(ctx, secp256k1_ecdsa_signature); - - if (!db_col_signature(stmt, "remote_ann_node_sig", *remote_ann_node_sig)) - goto fail; + if (!db_col_signature(stmt, "remote_ann_node_sig", remote_ann_node_sig)) + db_fatal(w->db, "Failed to decode remote_ann_node_sig for id %"PRIu64, chan->dbid); - if (!db_col_signature(stmt, "remote_ann_bitcoin_sig", *remote_ann_bitcoin_sig)) - goto fail; + if (!db_col_signature(stmt, "remote_ann_bitcoin_sig", remote_ann_bitcoin_sig)) + db_fatal(w->db, "Failed to decode remote_ann_bitcoin_sig for id %"PRIu64, chan->dbid); tal_free(stmt); return true; +} -fail: - *remote_ann_node_sig = tal_free(*remote_ann_node_sig); - *remote_ann_bitcoin_sig = tal_free(*remote_ann_bitcoin_sig); - tal_free(stmt); - return false; +void wallet_remote_ann_sigs_clear(struct wallet *w, const struct channel *chan) +{ + struct db_stmt *stmt; + stmt = db_prepare_v2(w->db, + SQL("UPDATE channels" + " SET remote_ann_node_sig=?, remote_ann_bitcoin_sig=?" + " WHERE id = ?")); + db_bind_null(stmt); + db_bind_null(stmt); + db_bind_u64(stmt, chan->dbid); + db_exec_prepared_v2(take(stmt)); } static struct fee_states *wallet_channel_fee_states_load(struct wallet *w, @@ -1759,7 +1763,8 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm htlc_minimum_msat, htlc_maximum_msat, ignore_fee_limits, - remote_update); + remote_update, + db_col_u64(stmt, "last_stable_connection")); if (!wallet_channel_load_inflights(w, chan)) { tal_free(chan); @@ -1796,6 +1801,7 @@ static struct closed_channel *wallet_stmt2closed_channel(const tal_t *ctx, cc->our_msat = db_col_amount_msat(stmt, "msatoshi_local"); cc->msat_to_us_min = db_col_amount_msat(stmt, "msatoshi_to_us_min"); cc->msat_to_us_max = db_col_amount_msat(stmt, "msatoshi_to_us_max"); + cc->last_stable_connection = db_col_u64(stmt, "last_stable_connection"); /* last_tx is null for stub channels used for recovering funds through * Static channel backups. */ if (!db_col_is_null(stmt, "last_tx")) @@ -1841,6 +1847,7 @@ struct closed_channel **wallet_load_closed_channels(const tal_t *ctx, ", channel_type" ", state_change_reason" ", lease_commit_sig" + ", last_stable_connection" " FROM channels" " LEFT JOIN peers p ON p.id = peer_id" " WHERE state = ?;")); @@ -1952,6 +1959,7 @@ static bool wallet_channels_load_active(struct wallet *w) ", remote_cltv_expiry_delta" ", remote_htlc_minimum_msat" ", remote_htlc_maximum_msat" + ", last_stable_connection" " FROM channels" " WHERE state != ?;")); //? 0 db_bind_int(stmt, CLOSED); @@ -2215,6 +2223,7 @@ void wallet_channel_save(struct wallet *w, struct channel *chan) { struct db_stmt *stmt; u8 *last_sent_commit; + const struct peer_update *peer_update; assert(chan->first_blocknum); wallet_channel_config_save(w, &chan->our_config); @@ -2270,8 +2279,9 @@ void wallet_channel_save(struct wallet *w, struct channel *chan) " remote_feerate_ppm=?," // 48 " remote_cltv_expiry_delta=?," // 49 " remote_htlc_minimum_msat=?," // 50 - " remote_htlc_maximum_msat=?" // 51 - " WHERE id=?")); // 52 + " remote_htlc_maximum_msat=?," + " last_stable_connection=?" + " WHERE id=?")); db_bind_u64(stmt, chan->their_shachain.id); if (chan->scid) db_bind_short_channel_id(stmt, chan->scid); @@ -2353,12 +2363,13 @@ void wallet_channel_save(struct wallet *w, struct channel *chan) db_bind_null(stmt); db_bind_int(stmt, chan->ignore_fee_limits); - if (chan->peer_update) { - db_bind_int(stmt, chan->peer_update->fee_base); - db_bind_int(stmt, chan->peer_update->fee_ppm); - db_bind_int(stmt, chan->peer_update->cltv_delta); - db_bind_amount_msat(stmt, &chan->peer_update->htlc_minimum_msat); - db_bind_amount_msat(stmt, &chan->peer_update->htlc_maximum_msat); + peer_update = channel_gossip_get_remote_update(chan); + if (peer_update) { + db_bind_int(stmt, peer_update->fee_base); + db_bind_int(stmt, peer_update->fee_ppm); + db_bind_int(stmt, peer_update->cltv_delta); + db_bind_amount_msat(stmt, &peer_update->htlc_minimum_msat); + db_bind_amount_msat(stmt, &peer_update->htlc_maximum_msat); } else { db_bind_null(stmt); db_bind_null(stmt); @@ -2366,6 +2377,7 @@ void wallet_channel_save(struct wallet *w, struct channel *chan) db_bind_null(stmt); db_bind_null(stmt); } + db_bind_u64(stmt, chan->last_stable_connection); db_bind_u64(stmt, chan->dbid); db_exec_prepared_v2(take(stmt)); @@ -2455,6 +2467,8 @@ void wallet_channel_save(struct wallet *w, struct channel *chan) db_bind_talarr(stmt, last_sent_commit); db_bind_u64(stmt, chan->dbid); db_exec_prepared_v2(take(stmt)); + + channel_gossip_update(chan); } void wallet_state_change_add(struct wallet *w, diff --git a/wallet/wallet.h b/wallet/wallet.h index 2e8138d5fcfb..904cd2301fac 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -1262,15 +1262,25 @@ bool wallet_forward_delete(struct wallet *w, /** * Load remote_ann_node_sig and remote_ann_bitcoin_sig * - * @ctx: allocation context for the return value * @w: wallet containing the channel - * @id: channel database id + * @chan: channel (must be in db) * @remote_ann_node_sig: location to load remote_ann_node_sig to * @remote_ann_bitcoin_sig: location to load remote_ann_bitcoin_sig to + * + * Returns false if the signatures were null. + */ +bool wallet_remote_ann_sigs_load(struct wallet *w, + const struct channel *chan, + secp256k1_ecdsa_signature *remote_ann_node_sig, + secp256k1_ecdsa_signature *remote_ann_bitcoin_sig); + +/** + * Null out remote_ann_node_sig and remote_ann_bitcoin_sig + * + * @w: wallet containing the channel + * @id: channel database id */ -bool wallet_remote_ann_sigs_load(const tal_t *ctx, struct wallet *w, u64 id, - secp256k1_ecdsa_signature **remote_ann_node_sig, - secp256k1_ecdsa_signature **remote_ann_bitcoin_sig); +void wallet_remote_ann_sigs_clear(struct wallet *w, const struct channel *chan); /** * Get a list of transactions that we track in the wallet.