Merge pull request #51 from TheBlueMatt/main
[ldk-c-bindings] / lightning-c-bindings / demo.cpp
index 230d0c0c92f762ad7a30a840108f72ab052461b3..2ee7a2938f819d4a9c965815cbb4f6bbae6ed79b 100644 (file)
@@ -1,12 +1,17 @@
 extern "C" {
-#include "include/rust_types.h"
-#include "include/lightning.h"
+#include <lightning.h>
+
+#ifdef REAL_NET
+#include <ldk_net.h>
+#endif
 }
 #include "include/lightningpp.hpp"
 
 #include <assert.h>
 #include <stdio.h>
 #include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
 #include <unistd.h>
 
 #include <atomic>
@@ -49,15 +54,13 @@ const uint8_t valid_node_announcement[] = {
 // A simple block containing only one transaction (which is the channel-open transaction for the
 // channel we'll create). This was originally created by printing additional data in a simple
 // rust-lightning unit test.
-const uint8_t channel_open_header[80] = {
+const uint8_t channel_open_block[] = {
        0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0xa2, 0x47, 0xd2, 0xf8, 0xd4, 0xe0, 0x6a, 0x3f, 0xf9, 0x7a, 0x9a, 0x34,
        0xbb, 0xa9, 0x96, 0xde, 0x63, 0x84, 0x5a, 0xce, 0xcf, 0x98, 0xb8, 0xbb, 0x75, 0x4c, 0x4f, 0x7d,
        0xee, 0x4c, 0xa9, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-const uint8_t channel_open_tx[] = {
+       0x01, // transaction count
        0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -74,37 +77,31 @@ const uint8_t channel_open_txid[] = {
 };
 
 // Two blocks built on top of channel_open_block:
-const uint8_t header_1[80] = {
-       0x01, 0x00, 0x00, 0x00, 0x65, 0x8e, 0xf1, 0x90, 0x88, 0xfa, 0x13, 0x9c, 0x6a, 0xea, 0xf7, 0xc1,
-       0x5a, 0xdd, 0x52, 0x4d, 0x3c, 0x48, 0x03, 0xb3, 0x9b, 0x25, 0x4f, 0x02, 0x79, 0x05, 0x90, 0xe0,
-       0xc4, 0x8d, 0xa0, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+const uint8_t block_1[81] = {
+       0x01, 0x00, 0x00, 0x00, 0x0c, 0x7a, 0xc2, 0xdc, 0x08, 0xaf, 0x40, 0x7d, 0x58, 0x81, 0x9b, 0x44,
+       0xc7, 0xe0, 0x0f, 0x78, 0xc0, 0xd1, 0x01, 0xa2, 0x03, 0x16, 0x4a, 0x8d, 0x92, 0x66, 0x4e, 0xaf,
+       0x7f, 0xfc, 0x6e, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, // transaction count
 };
-const uint8_t header_2[80] = {
-       0x01, 0x00, 0x00, 0x00, 0xf2, 0x08, 0x87, 0x51, 0xcb, 0xb1, 0x1a, 0x51, 0x76, 0x01, 0x6c, 0x5d,
-       0x76, 0x26, 0x54, 0x6f, 0xd9, 0xbd, 0xa6, 0xa5, 0xe9, 0x4b, 0x21, 0x6e, 0xda, 0xa3, 0x64, 0x23,
-       0xcd, 0xf1, 0xe2, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+const uint8_t block_2[81] = {
+       0x01, 0x00, 0x00, 0x00, 0x36, 0x0b, 0xf5, 0x46, 0x4a, 0xc7, 0x26, 0x4c, 0x4b, 0x36, 0xa6, 0x9d,
+       0x0e, 0xf0, 0x14, 0xfb, 0x8a, 0xcb, 0x20, 0x84, 0x18, 0xf3, 0xaa, 0x77, 0x32, 0x2d, 0xf7, 0x48,
+       0x62, 0x92, 0xb1, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-const LDKThirtyTwoBytes payment_preimage_1 = {
-       .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1 }
-};
-const LDKThirtyTwoBytes payment_hash_1 = {
-       .data = {
-               0xdc, 0xb1, 0xac, 0x4a, 0x5d, 0xe3, 0x70, 0xca, 0xd0, 0x91, 0xc1, 0x3f, 0x13, 0xae, 0xe2, 0xf9,
-               0x36, 0xc2, 0x78, 0xfa, 0x05, 0xd2, 0x64, 0x65, 0x3c, 0x0c, 0x13, 0x21, 0x85, 0x2a, 0x35, 0xe8
-       }
+       0x00, // transaction count
 };
 
 const LDKThirtyTwoBytes genesis_hash = { // We don't care particularly if this is "right"
        .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1 }
 };
 
-void print_log(const void *this_arg, const char *record) {
-       printf("%p - %s\n", this_arg, record);
+void print_log(const void *this_arg, const LDKRecord *record) {
+       LDK::Str mod = Record_get_module_path(record);
+       LDK::Str str = Record_get_args(record);
+       printf("%p - %.*s:%d - %.*s\n", this_arg, (int)mod->len, mod->chars, Record_get_line(record), (int)str->len, str->chars);
 }
 
 uint32_t get_fee(const void *this_arg, LDKConfirmationTarget target) {
@@ -137,7 +134,7 @@ struct NodeMonitors {
        void ConnectBlock(const uint8_t (*header)[80], uint32_t height, LDKCVec_C2Tuple_usizeTransactionZZ tx_data, LDKBroadcasterInterface broadcast, LDKFeeEstimator fee_est) {
                std::unique_lock<std::mutex> l(mut);
                for (auto& mon : mons) {
-                       LDK::CVec_C2Tuple_TxidCVec_C2Tuple_u32TxOutZZZZ res = ChannelMonitor_block_connected(&mon.second, &header_2, tx_data, height, broadcast, fee_est, *logger);
+                       LDK::CVec_TransactionOutputsZ res = ChannelMonitor_block_connected(&mon.second, header, tx_data, height, broadcast, fee_est, *logger);
                }
        }
 };
@@ -170,7 +167,7 @@ LDKCResult_NoneChannelMonitorUpdateErrZ update_channel_monitor(const void *this_
                        LDKBroadcasterInterface broadcaster = {
                                .broadcast_transaction = broadcast_tx,
                        };
-                       LDK::CResult_NoneMonitorUpdateErrorZ res = ChannelMonitor_update_monitor(&mon.second, &update, &broadcaster, &fee_est, arg->logger);
+                       LDK::CResult_NoneNoneZ res = ChannelMonitor_update_monitor(&mon.second, &update, &broadcaster, &fee_est, arg->logger);
                        assert(res->result_ok);
                }
        }
@@ -196,6 +193,80 @@ LDKCVec_MonitorEventZ monitors_pending_monitor_events(const void *this_arg) {
        }
 }
 
+struct EventQueue {
+       std::vector<LDK::Event> events;
+};
+void handle_event(const void *this_arg, const LDKEvent *event) {
+       EventQueue* arg = (EventQueue*) this_arg;
+       arg->events.push_back(Event_clone(event));
+}
+
+#ifdef REAL_NET
+class PeersConnection {
+       void* node1_handler;
+       void* node2_handler;
+
+public:
+       PeersConnection(LDK::ChannelManager& cm1, LDK::ChannelManager& cm2, LDK::PeerManager& net1, LDK::PeerManager& net2) {
+               node1_handler = init_socket_handling(&net1);
+               node2_handler = init_socket_handling(&net2);
+
+               struct sockaddr_in listen_addr;
+               listen_addr.sin_family = AF_INET;
+               listen_addr.sin_addr.s_addr = htonl((127 << 8*3) | 1);
+               listen_addr.sin_port = htons(10042);
+               assert(!socket_bind(node2_handler, (sockaddr*)&listen_addr, sizeof(listen_addr)));
+
+               assert(!socket_connect(node1_handler, ChannelManager_get_our_node_id(&cm2), (sockaddr*)&listen_addr, sizeof(listen_addr)));
+
+               while (true) {
+                       // Wait for the initial handshakes to complete...
+                       LDK::CVec_PublicKeyZ peers_1 = PeerManager_get_peer_node_ids(&net1);
+                       LDK::CVec_PublicKeyZ peers_2 = PeerManager_get_peer_node_ids(&net2);
+                       if (peers_1->datalen == 1 && peers_2->datalen == 1) { break; }
+                       std::this_thread::yield();
+               }
+
+               // Connect twice, which should auto-disconnect, and is a good test of our disconnect pipeline
+               assert(!socket_connect(node1_handler, ChannelManager_get_our_node_id(&cm2), (sockaddr*)&listen_addr, sizeof(listen_addr)));
+               assert(!socket_connect(node1_handler, ChannelManager_get_our_node_id(&cm2), (sockaddr*)&listen_addr, sizeof(listen_addr)));
+
+               // Then disconnect the "main" connection, while another connection is being made.
+               PeerManager_disconnect_by_node_id(&net1, ChannelManager_get_our_node_id(&cm2), false);
+               assert(!socket_connect(node1_handler, ChannelManager_get_our_node_id(&cm2), (sockaddr*)&listen_addr, sizeof(listen_addr)));
+
+               // Wait for all our sockets to disconnect (making sure we disconnect any new connections)...
+               while (true) {
+                       PeerManager_disconnect_by_node_id(&net1, ChannelManager_get_our_node_id(&cm2), false);
+                       // Wait for the peers to disconnect...
+                       LDK::CVec_PublicKeyZ peers_1 = PeerManager_get_peer_node_ids(&net1);
+                       LDK::CVec_PublicKeyZ peers_2 = PeerManager_get_peer_node_ids(&net2);
+                       if (peers_1->datalen == 0 && peers_2->datalen == 0) { break; }
+                       std::this_thread::yield();
+               }
+               // Note that the above is somewhat race-y, as node 2 may still think its connected.
+               // Thus, make sure any connections are disconnected on its end as well.
+               PeerManager_disconnect_by_node_id(&net2, ChannelManager_get_our_node_id(&cm1), false);
+
+               // Finally make an actual connection and keep it this time
+               assert(!socket_connect(node1_handler, ChannelManager_get_our_node_id(&cm2), (sockaddr*)&listen_addr, sizeof(listen_addr)));
+
+               while (true) {
+                       // Wait for the initial handshakes to complete...
+                       LDK::CVec_PublicKeyZ peers_1 = PeerManager_get_peer_node_ids(&net1);
+                       LDK::CVec_PublicKeyZ peers_2 = PeerManager_get_peer_node_ids(&net2);
+                       if (peers_1->datalen == 1 && peers_2->datalen == 1) { break; }
+                       std::this_thread::yield();
+               }
+       }
+       void stop() {
+               interrupt_socket_handling(node1_handler);
+               interrupt_socket_handling(node2_handler);
+       }
+};
+
+#else // REAL_NET
+
 uintptr_t sock_send_data(void *this_arg, LDKu8slice data, bool resume_read) {
        return write((int)((long)this_arg), data.data, data.datalen);
 }
@@ -242,7 +313,7 @@ public:
                        .disconnect_socket = sock_disconnect_socket,
                        .eq = sock_eq,
                        .hash = sock_hash,
-                       .clone = NULL,
+                       .cloned = NULL,
                        .free = NULL,
                };
 
@@ -252,7 +323,7 @@ public:
                        .disconnect_socket = sock_disconnect_socket,
                        .eq = sock_eq,
                        .hash = sock_hash,
-                       .clone = NULL,
+                       .cloned = NULL,
                        .free = NULL,
                };
 
@@ -286,8 +357,95 @@ public:
                t2.join();
        }
 };
+#endif // !REAL_NET
+
+struct CustomMsgQueue {
+       std::vector<LDK::Type> msgs;
+};
+
+uint16_t custom_msg_type_id(const void *this_arg) {
+       return 8888;
+}
+LDKCVec_u8Z custom_msg_bytes(const void *this_arg) {
+       uint8_t *bytes = (uint8_t *) malloc(1024);
+       memset(bytes, 42, 1024);
+       return LDKCVec_u8Z {
+               .data = bytes, .datalen = 1024
+       };
+}
+LDKStr custom_msg_debug(const void *this_arg) {
+       return LDKStr {
+               .chars = NULL, .len = 0, .chars_is_owned = false
+       };
+}
+
+LDKCResult_COption_TypeZDecodeErrorZ read_custom_message(const void* this_arg, uint16_t type_id, LDKu8slice buf) {
+       assert(type_id == 8888);
+       assert(buf.datalen == 1024);
+       uint8_t cmp[1024];
+       memset(cmp, 42, 1024);
+       assert(!memcmp(cmp, buf.data, 1024));
+       return CResult_COption_TypeZDecodeErrorZ_ok(COption_TypeZ_some(LDKType {
+               .this_arg = NULL,
+               .type_id = custom_msg_type_id,
+               .debug_str = custom_msg_debug,
+               .free = NULL,
+       }));
+}
+
+LDKCResult_NoneLightningErrorZ handle_custom_message(const void* this_arg, struct LDKType msg, struct LDKPublicKey _sender_node_id) {
+       CustomMsgQueue* arg = (CustomMsgQueue*) this_arg;
+       arg->msgs.push_back(std::move(msg));
+       return CResult_NoneLightningErrorZ_ok();
+}
+LDKCVec_C2Tuple_PublicKeyTypeZZ never_send_custom_msgs(const void* this_arg) {
+       return LDKCVec_C2Tuple_PublicKeyTypeZZ {
+               .data = NULL, .datalen = 0
+       };
+}
+
+LDKCVec_C2Tuple_PublicKeyTypeZZ create_custom_msg(const void* this_arg) {
+       const LDKPublicKey *counterparty_node_id = (const LDKPublicKey *)this_arg;
+       LDKCVec_C2Tuple_PublicKeyTypeZZ ret = {
+               .data = ((LDKC2Tuple_PublicKeyTypeZ*)malloc(sizeof(LDKC2Tuple_PublicKeyTypeZ))),
+               .datalen = 1
+       };
+       ret.data[0].a = *counterparty_node_id;
+       ret.data[0].b = LDKType {
+               .this_arg = NULL,
+               .type_id = custom_msg_type_id,
+               .debug_str = custom_msg_debug,
+               .write = custom_msg_bytes,
+               .free = NULL,
+       };
+       return ret;
+}
+
+uint64_t get_chan_score(const void *this_arg, uint64_t scid, uint64_t htlc_amt,
+LDKCOption_u64Z chan_capacity, const LDKNodeId *src, const LDKNodeId *dst) {
+       LDK::COption_u64Z _capacity(std::move(chan_capacity));
+       return 42;
+}
+
+struct CustomRouteFinderParams {
+       LDKLogger *logger;
+       LDKNetworkGraph *graph_ref;
+};
+struct LDKCResult_RouteLightningErrorZ custom_find_route(const void *this_arg, struct LDKPublicKey payer, const struct LDKRouteParameters *NONNULL_PTR route_params, const uint8_t (*payment_hash)[32], struct LDKCVec_ChannelDetailsZ *first_hops, const struct LDKScore *NONNULL_PTR scorer) {
+       const struct CustomRouteFinderParams *params = (struct CustomRouteFinderParams *)this_arg;
+       assert(first_hops->datalen == 1);
+       assert(ChannelDetails_get_is_usable(&first_hops->data[0]));
+       return find_route(payer, route_params, params->graph_ref, first_hops, *params->logger, scorer);
+}
 
 int main() {
+       uint8_t channel_open_header[80];
+       uint8_t header_1[80];
+       uint8_t header_2[80];
+       memcpy(channel_open_header, channel_open_block, 80);
+       memcpy(header_1, block_1, 80);
+       memcpy(header_2, block_2, 80);
+
        LDKPublicKey null_pk;
        memset(&null_pk, 0, sizeof(null_pk));
 
@@ -321,7 +479,8 @@ int main() {
                .free = NULL,
        };
 
-       LDK::NetGraphMsgHandler net_graph1 = NetGraphMsgHandler_new(genesis_hash, NULL, logger1);
+       LDK::NetworkGraph net_graph1 = NetworkGraph_new(genesis_hash);
+       LDK::NetGraphMsgHandler graph_msg_handler1 = NetGraphMsgHandler_new(&net_graph1, COption_AccessZ_none(), logger1);
        LDKSecretKey node_secret1;
 
        LDKLogger logger2 {
@@ -340,7 +499,8 @@ int main() {
                .free = NULL,
        };
 
-       LDK::NetGraphMsgHandler net_graph2 = NetGraphMsgHandler_new(genesis_hash, NULL, logger2);
+       LDK::NetworkGraph net_graph2 = NetworkGraph_new(genesis_hash);
+       LDK::NetGraphMsgHandler graph_msg_handler2 = NetGraphMsgHandler_new(&net_graph2, COption_AccessZ_none(), logger2);
        LDKSecretKey node_secret2;
 
        LDK::CVec_u8Z cm1_ser = LDKCVec_u8Z {}; // ChannelManager 1 serialization at the end of the ser-des scope
@@ -354,20 +514,23 @@ int main() {
                LDK::KeysInterface keys_source1 = KeysManager_as_KeysInterface(&keys1);
                node_secret1 = keys_source1->get_node_secret(keys_source1->this_arg);
 
-               LDK::ChannelManager cm1 = ChannelManager_new(fee_est, mon1, broadcast, logger1, KeysManager_as_KeysInterface(&keys1), UserConfig_default(), ChainParameters_new(network, chain_tip, 0));
+               LDK::ChannelManager cm1 = ChannelManager_new(fee_est, mon1, broadcast, logger1, KeysManager_as_KeysInterface(&keys1), UserConfig_default(), ChainParameters_new(network, BestBlock_new(chain_tip, 0)));
 
                LDK::CVec_ChannelDetailsZ channels = ChannelManager_list_channels(&cm1);
                assert(channels->datalen == 0);
 
-               LDK::MessageHandler msg_handler1 = MessageHandler_new(ChannelManager_as_ChannelMessageHandler(&cm1), NetGraphMsgHandler_as_RoutingMessageHandler(&net_graph1));
+               LDK::MessageHandler msg_handler1 = MessageHandler_new(ChannelManager_as_ChannelMessageHandler(&cm1), NetGraphMsgHandler_as_RoutingMessageHandler(&graph_msg_handler1));
+
+               LDK::IgnoringMessageHandler ignoring_handler1 = IgnoringMessageHandler_new();
+               LDK::CustomMessageHandler custom_msg_handler1 = IgnoringMessageHandler_as_CustomMessageHandler(&ignoring_handler1);
 
                random_bytes = keys_source1->get_secure_random_bytes(keys_source1->this_arg);
-               LDK::PeerManager net1 = PeerManager_new(std::move(msg_handler1), node_secret1, &random_bytes.data, logger1);
+               LDK::PeerManager net1 = PeerManager_new(std::move(msg_handler1), node_secret1, &random_bytes.data, logger1, std::move(custom_msg_handler1));
 
                // Demo getting a channel key and check that its returning real pubkeys:
                LDK::Sign chan_signer1 = keys_source1->get_channel_signer(keys_source1->this_arg, false, 42);
-               chan_signer1->set_pubkeys(&chan_signer1); // Make sure pubkeys is defined
-               LDKPublicKey payment_point = ChannelPublicKeys_get_payment_point(&chan_signer1->pubkeys);
+               chan_signer1->BaseSign.set_pubkeys(&chan_signer1->BaseSign); // Make sure pubkeys is defined
+               LDKPublicKey payment_point = ChannelPublicKeys_get_payment_point(&chan_signer1->BaseSign.pubkeys);
                assert(memcmp(&payment_point, &null_pk, sizeof(null_pk)));
 
                // Instantiate classes for node 2:
@@ -381,12 +544,12 @@ int main() {
                LDK::UserConfig config2 = UserConfig_default();
                UserConfig_set_own_channel_config(&config2, std::move(handshake_config2));
 
-               LDK::ChannelManager cm2 = ChannelManager_new(fee_est, mon2, broadcast, logger2, KeysManager_as_KeysInterface(&keys2), std::move(config2), ChainParameters_new(network, chain_tip, 0));
+               LDK::ChannelManager cm2 = ChannelManager_new(fee_est, mon2, broadcast, logger2, KeysManager_as_KeysInterface(&keys2), std::move(config2), ChainParameters_new(network, BestBlock_new(chain_tip, 0)));
 
                LDK::CVec_ChannelDetailsZ channels2 = ChannelManager_list_channels(&cm2);
                assert(channels2->datalen == 0);
 
-               LDK::RoutingMessageHandler net_msgs2 = NetGraphMsgHandler_as_RoutingMessageHandler(&net_graph2);
+               LDK::RoutingMessageHandler net_msgs2 = NetGraphMsgHandler_as_RoutingMessageHandler(&graph_msg_handler2);
                LDK::CResult_ChannelAnnouncementDecodeErrorZ chan_ann = ChannelAnnouncement_read(LDKu8slice { .data = valid_node_announcement, .datalen = sizeof(valid_node_announcement) });
                assert(chan_ann->result_ok);
                LDK::CResult_boolLightningErrorZ ann_res = net_msgs2->handle_channel_announcement(net_msgs2->this_arg, chan_ann->contents.result);
@@ -394,27 +557,32 @@ int main() {
 
                LDK::MessageHandler msg_handler2 = MessageHandler_new(ChannelManager_as_ChannelMessageHandler(&cm2), std::move(net_msgs2));
 
+               LDK::IgnoringMessageHandler ignoring_handler2 = IgnoringMessageHandler_new();
+               LDK::CustomMessageHandler custom_msg_handler2 = IgnoringMessageHandler_as_CustomMessageHandler(&ignoring_handler2);
+
                random_bytes = keys_source2->get_secure_random_bytes(keys_source2->this_arg);
-               LDK::PeerManager net2 = PeerManager_new(std::move(msg_handler2), node_secret2, &random_bytes.data, logger2);
+               LDK::PeerManager net2 = PeerManager_new(std::move(msg_handler2), node_secret2, &random_bytes.data, logger2, std::move(custom_msg_handler2));
 
                // Open a connection!
                PeersConnection conn(cm1, cm2, net1, net2);
 
                // Note that we have to bind the result to a C++ class to make sure it gets free'd
-               LDK::CResult_NoneAPIErrorZ res = ChannelManager_create_channel(&cm1, ChannelManager_get_our_node_id(&cm2), 40000, 1000, 42, UserConfig_default());
+               LDK::CResult__u832APIErrorZ res = ChannelManager_create_channel(&cm1, ChannelManager_get_our_node_id(&cm2), 40000, 1000, 42, UserConfig_default());
                assert(res->result_ok);
                PeerManager_process_events(&net1);
 
                LDK::CVec_ChannelDetailsZ new_channels = ChannelManager_list_channels(&cm1);
                assert(new_channels->datalen == 1);
-               LDKPublicKey chan_open_pk = ChannelDetails_get_remote_network_id(&new_channels->data[0]);
+               LDK::ChannelCounterparty new_channels_counterparty = ChannelDetails_get_counterparty(&new_channels->data[0]);
+               LDKPublicKey chan_open_pk = ChannelCounterparty_get_node_id(&new_channels_counterparty);
                assert(!memcmp(chan_open_pk.compressed_form, ChannelManager_get_our_node_id(&cm2).compressed_form, 33));
 
                while (true) {
                        LDK::CVec_ChannelDetailsZ new_channels_2 = ChannelManager_list_channels(&cm2);
                        if (new_channels_2->datalen == 1) {
                                // Sample getting our counterparty's init features (which used to be hard to do without a memory leak):
-                               const LDK::InitFeatures init_feats = ChannelDetails_get_counterparty_features(&new_channels_2->data[0]);
+                               LDK::ChannelCounterparty new_channels_2_counterparty = ChannelDetails_get_counterparty(&new_channels_2->data[0]);
+                               const LDK::InitFeatures init_feats = ChannelCounterparty_get_features(&new_channels_2_counterparty);
                                assert(init_feats->inner != NULL);
                                break;
                        }
@@ -423,17 +591,19 @@ int main() {
 
                LDKEventsProvider ev1 = ChannelManager_as_EventsProvider(&cm1);
                while (true) {
-                       LDK::CVec_EventZ events = ev1.get_and_clear_pending_events(ev1.this_arg);
-                       if (events->datalen == 1) {
-                               assert(events->data[0].tag == LDKEvent_FundingGenerationReady);
-                               assert(events->data[0].funding_generation_ready.user_channel_id == 42);
-                               assert(events->data[0].funding_generation_ready.channel_value_satoshis == 40000);
-                               assert(events->data[0].funding_generation_ready.output_script.datalen == 34);
-                               assert(!memcmp(events->data[0].funding_generation_ready.output_script.data, channel_open_tx + 58, 34));
-                               LDKThirtyTwoBytes txid;
-                               for (int i = 0; i < 32; i++) { txid.data[i] = channel_open_txid[31-i]; }
-                               LDK::OutPoint outp = OutPoint_new(txid, 0);
-                               ChannelManager_funding_transaction_generated(&cm1, &events->data[0].funding_generation_ready.temporary_channel_id.data, std::move(outp));
+                       EventQueue queue;
+                       LDKEventHandler handler = { .this_arg = &queue, .handle_event = handle_event, .free = NULL };
+                       ev1.process_pending_events(ev1.this_arg, handler);
+                       if (queue.events.size() == 1) {
+                               assert(queue.events[0]->tag == LDKEvent_FundingGenerationReady);
+                               assert(queue.events[0]->funding_generation_ready.user_channel_id == 42);
+                               assert(queue.events[0]->funding_generation_ready.channel_value_satoshis == 40000);
+                               assert(queue.events[0]->funding_generation_ready.output_script.datalen == 34);
+                               assert(!memcmp(queue.events[0]->funding_generation_ready.output_script.data, channel_open_block + 58 + 81, 34));
+                               LDKTransaction funding_transaction { .data = const_cast<uint8_t*>(channel_open_block + 81), .datalen = sizeof(channel_open_block) - 81, .data_is_owned = false };
+
+                               LDK::CResult_NoneAPIErrorZ fund_res = ChannelManager_funding_transaction_generated(&cm1, &queue.events[0]->funding_generation_ready.temporary_channel_id.data, funding_transaction);
+                               assert(fund_res->result_ok);
                                break;
                        }
                        std::this_thread::yield();
@@ -441,40 +611,33 @@ int main() {
 
                // We observe when the funding signed messages have been exchanged by
                // waiting for two monitors to be registered.
+               assert(num_txs_broadcasted == 0);
                PeerManager_process_events(&net1);
-               while (true) {
-                       LDK::CVec_EventZ events = ev1.get_and_clear_pending_events(ev1.this_arg);
-                       if (events->datalen == 1) {
-                               assert(events->data[0].tag == LDKEvent_FundingBroadcastSafe);
-                               assert(events->data[0].funding_broadcast_safe.user_channel_id == 42);
-                               break;
-                       }
+               while (num_txs_broadcasted != 1) {
                        std::this_thread::yield();
                }
 
-               LDKCVec_C2Tuple_usizeTransactionZZ txdata { .data = (LDKC2Tuple_usizeTransactionZ*)malloc(sizeof(LDKC2Tuple_usizeTransactionZ)), .datalen = 1 };
-               *txdata.data = C2Tuple_usizeTransactionZ_new(0, LDKTransaction { .data = (uint8_t*)channel_open_tx, .datalen = sizeof(channel_open_tx), .data_is_owned = false });
-               ChannelManager_block_connected(&cm1, &channel_open_header, txdata, 1);
+               LDK::Listen listener1 = ChannelManager_as_Listen(&cm1);
+               listener1->block_connected(listener1->this_arg, LDKu8slice { .data = channel_open_block, .datalen = sizeof(channel_open_block) }, 1);
 
-               txdata = LDKCVec_C2Tuple_usizeTransactionZZ { .data = (LDKC2Tuple_usizeTransactionZ*)malloc(sizeof(LDKC2Tuple_usizeTransactionZ)), .datalen = 1 };
-               *txdata.data = C2Tuple_usizeTransactionZ_new(0, LDKTransaction { .data = (uint8_t*)channel_open_tx, .datalen = sizeof(channel_open_tx), .data_is_owned = false });
-               ChannelManager_block_connected(&cm2, &channel_open_header, txdata, 1);
+               LDK::Listen listener2 = ChannelManager_as_Listen(&cm2);
+               listener2->block_connected(listener2->this_arg, LDKu8slice { .data = channel_open_block, .datalen = sizeof(channel_open_block) }, 1);
 
-               txdata = LDKCVec_C2Tuple_usizeTransactionZZ { .data = (LDKC2Tuple_usizeTransactionZ*)malloc(sizeof(LDKC2Tuple_usizeTransactionZ)), .datalen = 1 };
-               *txdata.data = C2Tuple_usizeTransactionZ_new(0, LDKTransaction { .data = (uint8_t*)channel_open_tx, .datalen = sizeof(channel_open_tx), .data_is_owned = false });
+               LDKCVec_C2Tuple_usizeTransactionZZ txdata { .data = (LDKC2Tuple_usizeTransactionZ*)malloc(sizeof(LDKC2Tuple_usizeTransactionZ)), .datalen = 1 };
+               *txdata.data = C2Tuple_usizeTransactionZ_new(0, LDKTransaction { .data = (uint8_t*)channel_open_block + 81, .datalen = sizeof(channel_open_block) - 81, .data_is_owned = false });
                mons1.ConnectBlock(&channel_open_header, 1, txdata, broadcast, fee_est);
 
                txdata = LDKCVec_C2Tuple_usizeTransactionZZ { .data = (LDKC2Tuple_usizeTransactionZ*)malloc(sizeof(LDKC2Tuple_usizeTransactionZ)), .datalen = 1 };
-               *txdata.data = C2Tuple_usizeTransactionZ_new(0, LDKTransaction { .data = (uint8_t*)channel_open_tx, .datalen = sizeof(channel_open_tx), .data_is_owned = false });
+               *txdata.data = C2Tuple_usizeTransactionZ_new(0, LDKTransaction { .data = (uint8_t*)channel_open_block + 81, .datalen = sizeof(channel_open_block) - 81, .data_is_owned = false });
                mons2.ConnectBlock(&channel_open_header, 1, txdata, broadcast, fee_est);
 
-               ChannelManager_block_connected(&cm1, &header_1, LDKCVec_C2Tuple_usizeTransactionZZ { .data = NULL, .datalen = 0 }, 2);
-               ChannelManager_block_connected(&cm2, &header_1, LDKCVec_C2Tuple_usizeTransactionZZ { .data = NULL, .datalen = 0 }, 2);
+               listener1->block_connected(listener1->this_arg, LDKu8slice { .data = block_1, .datalen = sizeof(block_1) }, 2);
+               listener2->block_connected(listener2->this_arg, LDKu8slice { .data = block_1, .datalen = sizeof(block_1) }, 2);
                mons1.ConnectBlock(&header_1, 2, LDKCVec_C2Tuple_usizeTransactionZZ { .data = NULL, .datalen = 0 }, broadcast, fee_est);
                mons2.ConnectBlock(&header_1, 2, LDKCVec_C2Tuple_usizeTransactionZZ { .data = NULL, .datalen = 0 }, broadcast, fee_est);
 
-               ChannelManager_block_connected(&cm1, &header_2, LDKCVec_C2Tuple_usizeTransactionZZ { .data = NULL, .datalen = 0 }, 3);
-               ChannelManager_block_connected(&cm2, &header_2, LDKCVec_C2Tuple_usizeTransactionZZ { .data = NULL, .datalen = 0 }, 3);
+               listener1->block_connected(listener1->this_arg, LDKu8slice { .data = block_2, .datalen = sizeof(block_1) }, 3);
+               listener2->block_connected(listener2->this_arg, LDKu8slice { .data = block_2, .datalen = sizeof(block_1) }, 3);
                mons1.ConnectBlock(&header_2, 3, LDKCVec_C2Tuple_usizeTransactionZZ { .data = NULL, .datalen = 0 }, broadcast, fee_est);
                mons2.ConnectBlock(&header_2, 3, LDKCVec_C2Tuple_usizeTransactionZZ { .data = NULL, .datalen = 0 }, broadcast, fee_est);
 
@@ -482,37 +645,72 @@ int main() {
                PeerManager_process_events(&net2);
 
                // Now send funds from 1 to 2!
+               uint64_t channel_scid;
                while (true) {
                        LDK::CVec_ChannelDetailsZ outbound_channels = ChannelManager_list_usable_channels(&cm1);
                        if (outbound_channels->datalen == 1) {
                                const LDKChannelDetails *channel = &outbound_channels->data[0];
+                               LDK::ChannelCounterparty counterparty = ChannelDetails_get_counterparty(channel);
                                // Note that the channel ID is the same as the channel txid reversed as the output index is 0
                                uint8_t expected_chan_id[32];
                                for (int i = 0; i < 32; i++) { expected_chan_id[i] = channel_open_txid[31-i]; }
                                assert(!memcmp(ChannelDetails_get_channel_id(channel), expected_chan_id, 32));
-                               assert(!memcmp(ChannelDetails_get_remote_network_id(channel).compressed_form,
-                                               ChannelManager_get_our_node_id(&cm2).compressed_form, 33));
+                               assert(!memcmp(
+                                       ChannelCounterparty_get_node_id(&counterparty).compressed_form,
+                                       ChannelManager_get_our_node_id(&cm2).compressed_form, 33));
                                assert(ChannelDetails_get_channel_value_satoshis(channel) == 40000);
                                // We opened the channel with 1000 push_msat:
-                               assert(ChannelDetails_get_outbound_capacity_msat(channel) == 40000*1000 - 1000);
-                               assert(ChannelDetails_get_inbound_capacity_msat(channel) == 1000);
-                               assert(ChannelDetails_get_is_live(channel));
+                               assert(ChannelDetails_get_outbound_capacity_msat(channel) ==
+                                       40000*1000 - 1000 - 1000 * ChannelCounterparty_get_unspendable_punishment_reserve(&counterparty));
+                               int64_t inbound_capacity = ((int64_t)1000) - ChannelCounterparty_get_unspendable_punishment_reserve(&counterparty);
+                               if (inbound_capacity < 0) inbound_capacity = 0;
+                               assert(ChannelDetails_get_inbound_capacity_msat(channel) == (uint64_t)inbound_capacity);
+                               assert(ChannelDetails_get_is_usable(channel));
+                               LDK::COption_u64Z scid_opt = ChannelDetails_get_short_channel_id(channel);
+                               assert(scid_opt->some);
+                               channel_scid = scid_opt->some;
                                break;
                        }
                        std::this_thread::yield();
                }
 
-               LDK::CVec_ChannelDetailsZ outbound_channels = ChannelManager_list_usable_channels(&cm1);
-               LDKThirtyTwoBytes payment_secret;
-               memset(payment_secret.data, 0x42, 32);
+               LDKCOption_u64Z min_value = {
+                       .tag = LDKCOption_u64Z_Some,
+                       .some = 5000,
+               };
+               LDK::CResult_InvoiceSignOrCreationErrorZ invoice = create_invoice_from_channelmanager(&cm2,
+                       KeysManager_as_KeysInterface(&keys2),
+                       LDKCurrency_Bitcoin, min_value,
+                       LDKStr {
+                               .chars = (const uint8_t *)"Invoice Description",
+                               .len =             strlen("Invoice Description"),
+                               .chars_is_owned = false
+                       });
+               assert(invoice->result_ok);
+               LDKThirtyTwoBytes payment_hash;
+               memcpy(payment_hash.data, Invoice_payment_hash(invoice->contents.result), 32);
+
                {
-                       LDK::LockedNetworkGraph graph_2_locked = NetGraphMsgHandler_read_locked_graph(&net_graph2);
-                       LDK::NetworkGraph graph_2_ref = LockedNetworkGraph_graph(&graph_2_locked);
-                       LDK::CResult_RouteLightningErrorZ route = get_route(ChannelManager_get_our_node_id(&cm1), &graph_2_ref, ChannelManager_get_our_node_id(&cm2), &outbound_channels, LDKCVec_RouteHintZ {
-                                       .data = NULL, .datalen = 0
-                               }, 5000, 10, logger1);
+                       LDK::CVec_ChannelDetailsZ outbound_channels = ChannelManager_list_usable_channels(&cm1);
+                       LDK::Score chan_scorer = LDKScore {
+                               .this_arg = NULL, .channel_penalty_msat = get_chan_score, .free = NULL
+                       };
+                       LDK::RouteParameters route_params = RouteParameters_new(Payee_new(
+                                       ChannelManager_get_our_node_id(&cm2), LDKInvoiceFeatures {
+                                               .inner = NULL, .is_owned = false
+                                       }, Invoice_route_hints(invoice->contents.result), COption_u64Z_none()),
+                               5000, Invoice_min_final_cltv_expiry(invoice->contents.result));
+                       LDK::CResult_RouteLightningErrorZ route = find_route(ChannelManager_get_our_node_id(&cm1), &route_params, &net_graph2, &outbound_channels, logger1, &chan_scorer);
                        assert(route->result_ok);
-                       LDK::CResult_NonePaymentSendFailureZ send_res = ChannelManager_send_payment(&cm1, route->contents.result, payment_hash_1, payment_secret);
+                       LDK::CVec_CVec_RouteHopZZ paths = Route_get_paths(route->contents.result);
+                       assert(paths->datalen == 1);
+                       assert(paths->data[0].datalen == 1);
+                       assert(!memcmp(RouteHop_get_pubkey(&paths->data[0].data[0]).compressed_form,
+                               ChannelManager_get_our_node_id(&cm2).compressed_form, 33));
+                       assert(RouteHop_get_short_channel_id(&paths->data[0].data[0]) == channel_scid);
+                       LDKThirtyTwoBytes payment_secret;
+                       memcpy(payment_secret.data, Invoice_payment_secret(invoice->contents.result), 32);
+                       LDK::CResult_PaymentIdPaymentSendFailureZ send_res = ChannelManager_send_payment(&cm1, route->contents.result, payment_hash, payment_secret);
                        assert(send_res->result_ok);
                }
 
@@ -523,11 +721,13 @@ int main() {
                }
 
                // Check that we received the payment!
-               LDKEventsProvider ev2 = ChannelManager_as_EventsProvider(&cm2);
+               LDK::EventsProvider ev2 = ChannelManager_as_EventsProvider(&cm2);
                while (true) {
-                       LDK::CVec_EventZ events = ev2.get_and_clear_pending_events(ev2.this_arg);
-                       if (events->datalen == 1) {
-                               assert(events->data[0].tag == LDKEvent_PendingHTLCsForwardable);
+                       EventQueue queue;
+                       LDKEventHandler handler = { .this_arg = &queue, .handle_event = handle_event, .free = NULL };
+                       ev2.process_pending_events(handler);
+                       if (queue.events.size() == 1) {
+                               assert(queue.events[0]->tag == LDKEvent_PendingHTLCsForwardable);
                                break;
                        }
                        std::this_thread::yield();
@@ -536,14 +736,20 @@ int main() {
                PeerManager_process_events(&net2);
 
                mons_updated = 0;
+               LDKThirtyTwoBytes payment_preimage;
                {
-                       LDK::CVec_EventZ events = ev2.get_and_clear_pending_events(ev2.this_arg);
-                       assert(events->datalen == 1);
-                       assert(events->data[0].tag == LDKEvent_PaymentReceived);
-                       assert(!memcmp(events->data[0].payment_received.payment_hash.data, payment_hash_1.data, 32));
-                       assert(!memcmp(events->data[0].payment_received.payment_secret.data, payment_secret.data, 32));
-                       assert(events->data[0].payment_received.amt == 5000);
-                       assert(ChannelManager_claim_funds(&cm2, payment_preimage_1, payment_secret, 5000));
+                       EventQueue queue;
+                       LDKEventHandler handler = { .this_arg = &queue, .handle_event = handle_event, .free = NULL };
+                       ev2.process_pending_events(handler);
+                       assert(queue.events.size() == 1);
+                       assert(queue.events[0]->tag == LDKEvent_PaymentReceived);
+                       assert(!memcmp(queue.events[0]->payment_received.payment_hash.data, payment_hash.data, 32));
+                       assert(queue.events[0]->payment_received.purpose.tag == LDKPaymentPurpose_InvoicePayment);
+                       assert(!memcmp(queue.events[0]->payment_received.purpose.invoice_payment.payment_secret.data,
+                                       Invoice_payment_secret(invoice->contents.result), 32));
+                       assert(queue.events[0]->payment_received.amt == 5000);
+                       memcpy(payment_preimage.data, queue.events[0]->payment_received.purpose.invoice_payment.payment_preimage.data, 32);
+                       assert(ChannelManager_claim_funds(&cm2, payment_preimage));
                }
                PeerManager_process_events(&net2);
                // Wait until we've passed through a full set of monitor updates (ie new preimage + CS/RAA messages)
@@ -551,10 +757,15 @@ int main() {
                        std::this_thread::yield();
                }
                {
-                       LDK::CVec_EventZ events = ev1.get_and_clear_pending_events(ev1.this_arg);
-                       assert(events->datalen == 1);
-                       assert(events->data[0].tag == LDKEvent_PaymentSent);
-                       assert(!memcmp(events->data[0].payment_sent.payment_preimage.data, payment_preimage_1.data, 32));
+                       EventQueue queue;
+                       LDKEventHandler handler = { .this_arg = &queue, .handle_event = handle_event, .free = NULL };
+                       while (queue.events.size() < 2)
+                               ev1.process_pending_events(ev1.this_arg, handler);
+                       assert(queue.events.size() == 2);
+                       assert(queue.events[0]->tag == LDKEvent_PaymentSent);
+                       assert(!memcmp(queue.events[0]->payment_sent.payment_preimage.data, payment_preimage.data, 32));
+                       assert(queue.events[1]->tag == LDKEvent_PaymentPathSuccessful);
+                       assert(!memcmp(queue.events[1]->payment_path_successful.payment_hash.data, payment_hash.data, 32));
                }
 
                conn.stop();
@@ -598,13 +809,38 @@ int main() {
        assert(!close_res->result_ok); // Note that we can't close while disconnected!
 
        // Open a connection!
-       LDK::MessageHandler msg_handler1 = MessageHandler_new(ChannelManager_as_ChannelMessageHandler(&cm1), NetGraphMsgHandler_as_RoutingMessageHandler(&net_graph1));
+       LDK::MessageHandler msg_handler1 = MessageHandler_new(ChannelManager_as_ChannelMessageHandler(&cm1), NetGraphMsgHandler_as_RoutingMessageHandler(&graph_msg_handler1));
        random_bytes = keys_source1->get_secure_random_bytes(keys_source1->this_arg);
-       LDK::PeerManager net1 = PeerManager_new(std::move(msg_handler1), node_secret1, &random_bytes.data, logger1);
 
-       LDK::MessageHandler msg_handler2 = MessageHandler_new(ChannelManager_as_ChannelMessageHandler(&cm2), NetGraphMsgHandler_as_RoutingMessageHandler(&net_graph2));
+       LDKPublicKey chan_2_node_id = ChannelManager_get_our_node_id(&cm2);
+       LDKCustomMessageHandler custom_msg_handler1 = {
+               .this_arg = &chan_2_node_id,
+               .handle_custom_message = NULL, // We only create custom messages, not handle them
+               .get_and_clear_pending_msg = create_custom_msg,
+               .CustomMessageReader = LDKCustomMessageReader {
+                       .this_arg = NULL,
+                       .read = read_custom_message,
+                       .free = NULL,
+               },
+               .free = NULL,
+       };
+       LDK::PeerManager net1 = PeerManager_new(std::move(msg_handler1), node_secret1, &random_bytes.data, logger1, std::move(custom_msg_handler1));
+
+       LDK::MessageHandler msg_handler2 = MessageHandler_new(ChannelManager_as_ChannelMessageHandler(&cm2), NetGraphMsgHandler_as_RoutingMessageHandler(&graph_msg_handler2));
+       CustomMsgQueue peer_2_custom_messages;
+       LDKCustomMessageHandler custom_msg_handler2 = {
+               .this_arg = &peer_2_custom_messages,
+               .handle_custom_message = handle_custom_message,
+               .get_and_clear_pending_msg = never_send_custom_msgs,
+               .CustomMessageReader = LDKCustomMessageReader {
+                       .this_arg = NULL,
+                       .read = read_custom_message,
+                       .free = NULL,
+               },
+               .free = NULL,
+       };
        random_bytes = keys_source1->get_secure_random_bytes(keys_source1->this_arg);
-       LDK::PeerManager net2 = PeerManager_new(std::move(msg_handler2), node_secret2, &random_bytes.data, logger2);
+       LDK::PeerManager net2 = PeerManager_new(std::move(msg_handler2), node_secret2, &random_bytes.data, logger2, std::move(custom_msg_handler2));
 
        PeersConnection conn(cm1, cm2, net1, net2);
 
@@ -616,11 +852,87 @@ int main() {
                }
        }
 
+       // Send another payment, this time via the InvoicePayer
+       struct CustomRouteFinderParams router_params = {
+               .logger = &logger1,
+               .graph_ref = &net_graph1,
+       };
+       LDKRouter sending_router = {
+               .this_arg = &router_params,
+               .find_route = custom_find_route,
+               .free = NULL,
+       };
+       LDK::Scorer scorer = Scorer_default();
+       LDK::MultiThreadedLockableScore scorer_mtx = MultiThreadedLockableScore_new(Scorer_as_Score(&scorer));
+       EventQueue queue1;
+       LDKEventHandler handler1 = { .this_arg = &queue1, .handle_event = handle_event, .free = NULL };
+       LDK::InvoicePayer payer = InvoicePayer_new(ChannelManager_as_Payer(&cm1), sending_router, &scorer_mtx, logger1, handler1, RetryAttempts_new(0));
+
+       LDK::CResult_InvoiceSignOrCreationErrorZ invoice_res2 = create_invoice_from_channelmanager(&cm2,
+               KeysManager_as_KeysInterface(&keys2),
+               LDKCurrency_Bitcoin, COption_u64Z_some(10000),
+               LDKStr {
+                       .chars = (const uint8_t *)"Invoice 2 Description",
+                       .len =             strlen("Invoice 2 Description"),
+                       .chars_is_owned = false
+               });
+       assert(invoice_res2->result_ok);
+       const LDKInvoice *invoice2 = invoice_res2->contents.result;
+       LDK::CResult_PaymentIdPaymentErrorZ invoice_pay_res = InvoicePayer_pay_invoice(&payer, invoice2);
+       assert(invoice_pay_res->result_ok);
+       PeerManager_process_events(&net1);
+
+       // Check that we received the payment!
+       while (true) {
+               EventQueue queue2;
+               LDKEventHandler handler2 = { .this_arg = &queue2, .handle_event = handle_event, .free = NULL };
+               LDK::EventsProvider ev2 = ChannelManager_as_EventsProvider(&cm2);
+               ev2.process_pending_events(handler2);
+               if (queue2.events.size() == 1) {
+                       assert(queue2.events[0]->tag == LDKEvent_PendingHTLCsForwardable);
+                       break;
+               }
+               std::this_thread::yield();
+       }
+       ChannelManager_process_pending_htlc_forwards(&cm2);
+       PeerManager_process_events(&net2);
+
+       while (true) {
+               EventQueue queue2;
+               LDKEventHandler handler2 = { .this_arg = &queue2, .handle_event = handle_event, .free = NULL };
+               LDK::EventsProvider ev2 = ChannelManager_as_EventsProvider(&cm2);
+               ev2.process_pending_events(handler2);
+               if (queue2.events.size() == 1) {
+                       assert(queue2.events[0]->tag == LDKEvent_PaymentReceived);
+                       const struct LDKEvent_LDKPaymentReceived_Body *event_data = &queue2.events[0]->payment_received;
+                       assert(!memcmp(event_data->payment_hash.data, Invoice_payment_hash(invoice2), 32));
+                       assert(event_data->purpose.tag == LDKPaymentPurpose_InvoicePayment);
+                       assert(!memcmp(event_data->purpose.invoice_payment.payment_secret.data,
+                                       Invoice_payment_secret(invoice2), 32));
+                       assert(event_data->amt == 10000);
+                       assert(ChannelManager_claim_funds(&cm2, event_data->purpose.invoice_payment.payment_preimage));
+                       break;
+               }
+               std::this_thread::yield();
+       }
+
+       while (queue1.events.size() < 2) {
+               PeerManager_process_events(&net2);
+               PeerManager_process_events(&net1);
+
+               LDK::EventsProvider ev1 = ChannelManager_as_EventsProvider(&cm1);
+               LDK::EventHandler evh1 = InvoicePayer_as_EventHandler(&payer);
+               ev1.process_pending_events(std::move(evh1));
+       }
+       assert(queue1.events.size() == 2);
+       assert(queue1.events[0]->tag == LDKEvent_PaymentSent);
+       assert(queue1.events[1]->tag == LDKEvent_PaymentPathSuccessful);
+
        // Actually close the channel
+       num_txs_broadcasted = 0;
        close_res = ChannelManager_close_channel(&cm1, &chan_id);
        assert(close_res->result_ok);
        PeerManager_process_events(&net1);
-       num_txs_broadcasted = 0;
        while (num_txs_broadcasted != 2) {
                std::this_thread::yield();
        }
@@ -631,6 +943,8 @@ int main() {
 
        conn.stop();
 
+       assert(peer_2_custom_messages.msgs.size() != 0);
+
        // Few extra random tests:
        LDKSecretKey sk;
        memset(&sk, 42, 32);