Update C/C++ demos for latest upstream API
[ldk-c-bindings] / lightning-c-bindings / demo.cpp
index 230d0c0c92f762ad7a30a840108f72ab052461b3..fd716b6d46a5ba413bc11d5a79a269322e5d2642 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,12 +134,12 @@ 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);
                }
        }
 };
 
-LDKCResult_NoneChannelMonitorUpdateErrZ add_channel_monitor(const void *this_arg, LDKOutPoint funding_txo_arg, LDKChannelMonitor monitor_arg) {
+LDKChannelMonitorUpdateStatus add_channel_monitor(const void *this_arg, LDKOutPoint funding_txo_arg, LDKChannelMonitor monitor_arg) {
        // First bind the args to C++ objects so they auto-free
        LDK::ChannelMonitor mon(std::move(monitor_arg));
        LDK::OutPoint funding_txo(std::move(funding_txo_arg));
@@ -151,10 +148,10 @@ LDKCResult_NoneChannelMonitorUpdateErrZ add_channel_monitor(const void *this_arg
        std::unique_lock<std::mutex> l(arg->mut);
 
        arg->mons.push_back(std::make_pair(std::move(funding_txo), std::move(mon)));
-       return CResult_NoneChannelMonitorUpdateErrZ_ok();
+       return ChannelMonitorUpdateStatus_completed();
 }
 static std::atomic_int mons_updated(0);
-LDKCResult_NoneChannelMonitorUpdateErrZ update_channel_monitor(const void *this_arg, LDKOutPoint funding_txo_arg, LDKChannelMonitorUpdate monitor_arg) {
+LDKChannelMonitorUpdateStatus update_channel_monitor(const void *this_arg, LDKOutPoint funding_txo_arg, LDKChannelMonitorUpdate monitor_arg) {
        // First bind the args to C++ objects so they auto-free
        LDK::ChannelMonitorUpdate update(std::move(monitor_arg));
        LDK::OutPoint funding_txo(std::move(funding_txo_arg));
@@ -170,21 +167,21 @@ 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);
                }
        }
        assert(updated);
 
        mons_updated += 1;
-       return CResult_NoneChannelMonitorUpdateErrZ_ok();
+       return ChannelMonitorUpdateStatus_completed();
 }
-LDKCVec_MonitorEventZ monitors_pending_monitor_events(const void *this_arg) {
+LDKCVec_C3Tuple_OutPointCVec_MonitorEventZPublicKeyZZ monitors_pending_monitor_events(const void *this_arg) {
        NodeMonitors* arg = (NodeMonitors*) this_arg;
        std::unique_lock<std::mutex> l(arg->mut);
 
        if (arg->mons.size() == 0) {
-               return LDKCVec_MonitorEventZ {
+               return LDKCVec_C3Tuple_OutPointCVec_MonitorEventZPublicKeyZZ {
                        .data = NULL,
                        .datalen = 0,
                };
@@ -192,10 +189,94 @@ LDKCVec_MonitorEventZ monitors_pending_monitor_events(const void *this_arg) {
                // We only ever actually have one channel per node, plus concatenating two
                // Rust Vecs to each other from C++ will require a bit of effort.
                assert(arg->mons.size() == 1);
-               return ChannelMonitor_get_and_clear_pending_monitor_events(&arg->mons[0].second);
+               LDK::CVec_MonitorEventZ events = ChannelMonitor_get_and_clear_pending_monitor_events(&arg->mons[0].second);
+               LDK::C2Tuple_OutPointScriptZ funding_info = ChannelMonitor_get_funding_txo(&arg->mons[0].second);
+               LDK::OutPoint outpoint = std::move(funding_info->a);
+               LDKPublicKey counterparty_node_id = ChannelMonitor_get_counterparty_node_id(&arg->mons[0].second);
+               LDK::C3Tuple_OutPointCVec_MonitorEventZPublicKeyZ tuple = C3Tuple_OutPointCVec_MonitorEventZPublicKeyZ_new(std::move(outpoint), std::move(events), std::move(counterparty_node_id));
+               auto vec = LDKCVec_C3Tuple_OutPointCVec_MonitorEventZPublicKeyZZ {
+                       .data = (LDKC3Tuple_OutPointCVec_MonitorEventZPublicKeyZ*)malloc(sizeof(LDKC3Tuple_OutPointCVec_MonitorEventZPublicKeyZ)),
+                       .datalen = 1,
+               };
+               vec.data[0] = std::move(tuple);
+               return vec;
        }
 }
 
+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 +323,7 @@ public:
                        .disconnect_socket = sock_disconnect_socket,
                        .eq = sock_eq,
                        .hash = sock_hash,
-                       .clone = NULL,
+                       .cloned = NULL,
                        .free = NULL,
                };
 
@@ -252,7 +333,7 @@ public:
                        .disconnect_socket = sock_disconnect_socket,
                        .eq = sock_eq,
                        .hash = sock_hash,
-                       .clone = NULL,
+                       .cloned = NULL,
                        .free = NULL,
                };
 
@@ -260,9 +341,9 @@ public:
                t2 = std::thread(&sock_read_data_thread, pipefds_1_to_2[0], &sock2, &net2);
 
                // Note that we have to bind the result to a C++ class to make sure it gets free'd
-               LDK::CResult_CVec_u8ZPeerHandleErrorZ con_res = PeerManager_new_outbound_connection(&net1, ChannelManager_get_our_node_id(&cm2), sock1);
+               LDK::CResult_CVec_u8ZPeerHandleErrorZ con_res = PeerManager_new_outbound_connection(&net1, ChannelManager_get_our_node_id(&cm2), sock1, COption_NetAddressZ_none());
                assert(con_res->result_ok);
-               LDK::CResult_NonePeerHandleErrorZ con_res2 = PeerManager_new_inbound_connection(&net2, sock2);
+               LDK::CResult_NonePeerHandleErrorZ con_res2 = PeerManager_new_inbound_connection(&net2, sock2, COption_NetAddressZ_none());
                assert(con_res2->result_ok);
 
                auto writelen = write(pipefds_1_to_2[1], con_res->contents.result->data, con_res->contents.result->datalen);
@@ -286,8 +367,143 @@ public:
                t2.join();
        }
 };
+#endif // !REAL_NET
+
+struct CustomOnionMsgQueue {
+       std::mutex mtx;
+       std::vector<LDK::CustomOnionMessageContents> msgs;
+};
+
+uint64_t custom_onion_msg_type_id(const void *this_arg) {
+       return 8888;
+}
+LDKCVec_u8Z custom_onion_msg_bytes(const void *this_arg) {
+       uint8_t *bytes = (uint8_t *) malloc(1024);
+       memset(bytes, 43, 1024);
+       return LDKCVec_u8Z {
+               .data = bytes, .datalen = 1024
+       };
+}
+
+void handle_custom_onion_message(const void* this_arg, struct LDKCustomOnionMessageContents msg) {
+       CustomOnionMsgQueue* arg = (CustomOnionMsgQueue*) this_arg;
+       std::unique_lock<std::mutex> lck(arg->mtx);
+       arg->msgs.push_back(std::move(msg));
+}
+
+LDKCustomOnionMessageContents build_custom_onion_message() {
+       return LDKCustomOnionMessageContents {
+               .this_arg = NULL,
+               .tlv_type = custom_onion_msg_type_id,
+               .write = custom_onion_msg_bytes,
+               .free = NULL,
+       };
+}
+
+LDKCResult_COption_CustomOnionMessageContentsZDecodeErrorZ read_custom_onion_message(const void* this_arg, uint64_t type, LDKu8slice buf) {
+       assert(type == 8888);
+       assert(buf.datalen == 1024);
+       uint8_t cmp[1024];
+       memset(cmp, 43, 1024);
+       assert(!memcmp(cmp, buf.data, 1024));
+       return CResult_COption_CustomOnionMessageContentsZDecodeErrorZ_ok(COption_CustomOnionMessageContentsZ_some(build_custom_onion_message()));
+}
+
+
+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, const LDKNodeId *src, const LDKNodeId *dst, LDKChannelUsage usage_in) {
+       LDK::ChannelUsage usage(std::move(usage_in));
+       return 42;
+}
+
+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 LDKInFlightHtlcs in_flights) {
+       const LDK::DefaultRouter *router = (LDK::DefaultRouter *)this_arg;
+       assert(first_hops->datalen == 1);
+       assert(ChannelDetails_get_is_usable(&first_hops->data[0]));
+       const LDK::Router router_impl = DefaultRouter_as_Router(&*router);
+       return router_impl->find_route(router_impl->this_arg, payer, route_params, payment_hash, first_hops, in_flights);
+}
+
+void custom_notify_payment_path_failed(const void *this_arg, struct LDKCVec_RouteHopZ path, uint64_t short_channel_id) {
+       const LDK::DefaultRouter *router = (LDK::DefaultRouter *)this_arg;
+       const LDK::Router router_impl = DefaultRouter_as_Router(&*router);
+       return router_impl->notify_payment_path_failed(router_impl->this_arg, path, short_channel_id);
+}
+void custom_notify_payment_path_successful(const void *this_arg, struct LDKCVec_RouteHopZ path) {
+       const LDK::DefaultRouter *router = (LDK::DefaultRouter *)this_arg;
+       const LDK::Router router_impl = DefaultRouter_as_Router(&*router);
+       return router_impl->notify_payment_path_successful(router_impl->this_arg, path);
+}
 
 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 +537,8 @@ int main() {
                .free = NULL,
        };
 
-       LDK::NetGraphMsgHandler net_graph1 = NetGraphMsgHandler_new(genesis_hash, NULL, logger1);
+       LDK::NetworkGraph net_graph1 = NetworkGraph_new(genesis_hash, logger1);
+       LDK::P2PGossipSync graph_msg_handler1 = P2PGossipSync_new(&net_graph1, COption_AccessZ_none(), logger1);
        LDKSecretKey node_secret1;
 
        LDKLogger logger2 {
@@ -340,7 +557,8 @@ int main() {
                .free = NULL,
        };
 
-       LDK::NetGraphMsgHandler net_graph2 = NetGraphMsgHandler_new(genesis_hash, NULL, logger2);
+       LDK::NetworkGraph net_graph2 = NetworkGraph_new(genesis_hash, logger2);
+       LDK::P2PGossipSync graph_msg_handler2 = P2PGossipSync_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
@@ -352,69 +570,87 @@ int main() {
                memset(&node_seed, 0, 32);
                LDK::KeysManager keys1 = KeysManager_new(&node_seed, 0, 0);
                LDK::KeysInterface keys_source1 = KeysManager_as_KeysInterface(&keys1);
-               node_secret1 = keys_source1->get_node_secret(keys_source1->this_arg);
+               LDK::CResult_SecretKeyNoneZ node_secret1_res = keys_source1->get_node_secret(keys_source1->this_arg, LDKRecipient_Node);
+               assert(node_secret1_res->result_ok);
+               node_secret1 = *node_secret1_res->contents.result;
+
+               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::IgnoringMessageHandler ignoring_handler1 = IgnoringMessageHandler_new();
+               LDK::CustomMessageHandler custom_msg_handler1 = IgnoringMessageHandler_as_CustomMessageHandler(&ignoring_handler1);
+               LDK::CustomOnionMessageHandler custom_onion_msg_handler1 = IgnoringMessageHandler_as_CustomOnionMessageHandler(&ignoring_handler1);
 
-               LDK::ChannelManager cm1 = ChannelManager_new(fee_est, mon1, broadcast, logger1, KeysManager_as_KeysInterface(&keys1), UserConfig_default(), ChainParameters_new(network, chain_tip, 0));
+               LDK::OnionMessenger om1 = OnionMessenger_new(KeysManager_as_KeysInterface(&keys1), logger1, std::move(custom_onion_msg_handler1));
 
                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), P2PGossipSync_as_RoutingMessageHandler(&graph_msg_handler1), OnionMessenger_as_OnionMessageHandler(&om1));
 
                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, 0xdeadbeef, &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:
                memset(&node_seed, 1, 32);
                LDK::KeysManager keys2 = KeysManager_new(&node_seed, 0, 0);
                LDK::KeysInterface keys_source2 = KeysManager_as_KeysInterface(&keys2);
-               node_secret2 = keys_source2->get_node_secret(keys_source2->this_arg);
+               LDK::CResult_SecretKeyNoneZ node_secret2_res = keys_source2->get_node_secret(keys_source2->this_arg, LDKRecipient_Node);
+               assert(node_secret2_res->result_ok);
+               node_secret2 = *node_secret2_res->contents.result;
 
                LDK::ChannelHandshakeConfig handshake_config2 = ChannelHandshakeConfig_default();
                ChannelHandshakeConfig_set_minimum_depth(&handshake_config2, 2);
                LDK::UserConfig config2 = UserConfig_default();
-               UserConfig_set_own_channel_config(&config2, std::move(handshake_config2));
+               UserConfig_set_channel_handshake_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, BestBlock_new(chain_tip, 0)));
+
+               LDK::IgnoringMessageHandler ignoring_handler2 = IgnoringMessageHandler_new();
+               LDK::CustomMessageHandler custom_msg_handler2 = IgnoringMessageHandler_as_CustomMessageHandler(&ignoring_handler2);
+               LDK::CustomOnionMessageHandler custom_onion_msg_handler2 = IgnoringMessageHandler_as_CustomOnionMessageHandler(&ignoring_handler2);
 
-               LDK::ChannelManager cm2 = ChannelManager_new(fee_est, mon2, broadcast, logger2, KeysManager_as_KeysInterface(&keys2), std::move(config2), ChainParameters_new(network, chain_tip, 0));
+               LDK::OnionMessenger om2 = OnionMessenger_new(KeysManager_as_KeysInterface(&keys2), logger2, std::move(custom_onion_msg_handler2));
 
                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 = P2PGossipSync_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);
                assert(ann_res->result_ok);
 
-               LDK::MessageHandler msg_handler2 = MessageHandler_new(ChannelManager_as_ChannelMessageHandler(&cm2), std::move(net_msgs2));
+               LDK::MessageHandler msg_handler2 = MessageHandler_new(ChannelManager_as_ChannelMessageHandler(&cm2), std::move(net_msgs2), OnionMessenger_as_OnionMessageHandler(&om1));
 
                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, 0xdeadbeef, &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 +659,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, queue.events[0]->funding_generation_ready.counterparty_node_id, funding_transaction);
+                               assert(fund_res->result_ok);
                                break;
                        }
                        std::this_thread::yield();
@@ -441,40 +679,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 +713,76 @@ 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), logger2,
+                       LDKCurrency_Bitcoin, min_value,
+                       LDKStr {
+                               .chars = (const uint8_t *)"Invoice Description",
+                               .len =             strlen("Invoice Description"),
+                               .chars_is_owned = false
+                       }, 3600);
+               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(PaymentParameters_new(
+                                       ChannelManager_get_our_node_id(&cm2), LDKInvoiceFeatures {
+                                               .inner = NULL, .is_owned = false
+                                       }, Invoice_route_hints(invoice->contents.result), COption_u64Z_none(), 0xffffffff,
+                                       1, 2, LDKCVec_u64Z { .data = NULL, .datalen = 0 }),
+                               5000, Invoice_min_final_cltv_expiry(invoice->contents.result));
+                       random_bytes = keys_source1->get_secure_random_bytes(keys_source1->this_arg);
+
+                       LDK::CResult_RouteLightningErrorZ route = find_route(ChannelManager_get_our_node_id(&cm1), &route_params, &net_graph2, &outbound_channels, logger1, &chan_scorer, &random_bytes.data);
+
                        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 +793,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 +808,27 @@ 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.amount_msat == 5000);
+                       memcpy(payment_preimage.data, queue.events[0]->payment_received.purpose.invoice_payment.payment_preimage.data, 32);
+                       ChannelManager_claim_funds(&cm2, payment_preimage);
+
+                       queue.events.clear();
+                       ev2.process_pending_events(handler);
+                       assert(queue.events.size() == 1);
+                       assert(queue.events[0]->tag == LDKEvent_PaymentClaimed);
+                       assert(!memcmp(queue.events[0]->payment_claimed.payment_hash.data, payment_hash.data, 32));
+                       assert(queue.events[0]->payment_claimed.purpose.tag == LDKPaymentPurpose_InvoicePayment);
                }
                PeerManager_process_events(&net2);
                // Wait until we've passed through a full set of monitor updates (ie new preimage + CS/RAA messages)
@@ -551,10 +836,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();
@@ -578,6 +868,14 @@ int main() {
        assert(cm1_read->result_ok);
        LDK::ChannelManager cm1(std::move(cm1_read->contents.result->b));
 
+       LDKCustomOnionMessageHandler custom_onion_msg_handler1 = {
+               .this_arg = NULL,
+               .handle_custom_message = NULL, // We only create custom messages, not handle them
+               .read_custom_message = NULL, // We only create custom messages, not handle them
+               .free = NULL,
+       };
+       LDK::OnionMessenger om1 = OnionMessenger_new(KeysManager_as_KeysInterface(&keys1), logger1, custom_onion_msg_handler1);
+
        LDK::CVec_ChannelMonitorZ mons_list2 = LDKCVec_ChannelMonitorZ { .data = (LDKChannelMonitor*)malloc(sizeof(LDKChannelMonitor)), .datalen = 1 };
        assert(mons2.mons.size() == 1);
        mons_list2->data[0] = *& std::get<1>(mons2.mons[0]); // Note that we need a reference, thus need a raw clone here, which *& does.
@@ -591,20 +889,54 @@ int main() {
        assert(cm2_read->result_ok);
        LDK::ChannelManager cm2(std::move(cm2_read->contents.result->b));
 
+       CustomOnionMsgQueue peer_2_custom_onion_messages;
+       LDKCustomOnionMessageHandler custom_onion_msg_handler2 = {
+               .this_arg = &peer_2_custom_onion_messages,
+               .handle_custom_message = handle_custom_onion_message,
+               .read_custom_message = read_custom_onion_message,
+               .free = NULL,
+       };
+       LDK::OnionMessenger om2 = OnionMessenger_new(KeysManager_as_KeysInterface(&keys2), logger2, custom_onion_msg_handler2);
+
        // Attempt to close the channel...
        uint8_t chan_id[32];
        for (int i = 0; i < 32; i++) { chan_id[i] = channel_open_txid[31-i]; }
-       LDK::CResult_NoneAPIErrorZ close_res = ChannelManager_close_channel(&cm1, &chan_id);
+       LDK::CResult_NoneAPIErrorZ close_res = ChannelManager_close_channel(&cm1, &chan_id, ChannelManager_get_our_node_id(&cm2));
        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), P2PGossipSync_as_RoutingMessageHandler(&graph_msg_handler1), OnionMessenger_as_OnionMessageHandler(&om1));
        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, 0xdeadbeef, &random_bytes.data, logger1, std::move(custom_msg_handler1));
+
+       LDK::MessageHandler msg_handler2 = MessageHandler_new(ChannelManager_as_ChannelMessageHandler(&cm2), P2PGossipSync_as_RoutingMessageHandler(&graph_msg_handler2), OnionMessenger_as_OnionMessageHandler(&om2));
+       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, 0xdeadbeef, &random_bytes.data, logger2, std::move(custom_msg_handler2));
 
        PeersConnection conn(cm1, cm2, net1, net2);
 
@@ -616,11 +948,99 @@ int main() {
                }
        }
 
+       // Send another payment, this time via the InvoicePayer
+       LDK::ProbabilisticScorer scorer = ProbabilisticScorer_new(ProbabilisticScoringParameters_default(), &net_graph1, logger1);
+       LDK::Score scorer_trait = ProbabilisticScorer_as_Score(&scorer);
+       LDK::MultiThreadedLockableScore scorer_mtx = MultiThreadedLockableScore_new(std::move(scorer_trait));
+       LDK::LockableScore scorer_mtx_trait = MultiThreadedLockableScore_as_LockableScore(&scorer_mtx);
+       const LDK::DefaultRouter router = DefaultRouter_new(&net_graph1, logger1, keys_source1->get_secure_random_bytes(keys_source1->this_arg), std::move(scorer_mtx_trait));
+       LDKRouter sending_router = {
+               .this_arg = (void*)&router,
+               .find_route = custom_find_route,
+               .notify_payment_path_failed = custom_notify_payment_path_failed,
+               .notify_payment_path_successful = custom_notify_payment_path_successful,
+               // We don't probe, so we opt to crash if the probe functions are called.
+               .notify_payment_probe_successful = NULL,
+               .notify_payment_probe_failed = NULL,
+               .free = NULL,
+       };
+       EventQueue queue1;
+       LDKEventHandler handler1 = { .this_arg = &queue1, .handle_event = handle_event, .free = NULL };
+       LDK::InvoicePayer payer = InvoicePayer_new(ChannelManager_as_Payer(&cm1), sending_router, logger1, handler1, Retry_attempts(0));
+
+       LDK::CResult_InvoiceSignOrCreationErrorZ invoice_res2 = create_invoice_from_channelmanager(&cm2,
+               KeysManager_as_KeysInterface(&keys2), logger1,
+               LDKCurrency_Bitcoin, COption_u64Z_some(10000),
+               LDKStr {
+                       .chars = (const uint8_t *)"Invoice 2 Description",
+                       .len =             strlen("Invoice 2 Description"),
+                       .chars_is_owned = false
+               }, 3600);
+       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->amount_msat == 10000);
+                       ChannelManager_claim_funds(&cm2, event_data->purpose.invoice_payment.payment_preimage);
+
+                       queue2.events.clear();
+                       ev2.process_pending_events(handler2);
+                       assert(queue2.events.size() == 1);
+                       assert(queue2.events[0]->tag == LDKEvent_PaymentClaimed);
+                       assert(!memcmp(queue2.events[0]->payment_claimed.payment_hash.data, Invoice_payment_hash(invoice2), 32));
+                       assert(queue2.events[0]->payment_claimed.purpose.tag == LDKPaymentPurpose_InvoicePayment);
+
+                       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
-       close_res = ChannelManager_close_channel(&cm1, &chan_id);
+       num_txs_broadcasted = 0;
+       close_res = ChannelManager_close_channel(&cm1, &chan_id, ChannelManager_get_our_node_id(&cm2));
        assert(close_res->result_ok);
        PeerManager_process_events(&net1);
-       num_txs_broadcasted = 0;
        while (num_txs_broadcasted != 2) {
                std::this_thread::yield();
        }
@@ -629,12 +1049,29 @@ int main() {
        LDK::CVec_ChannelDetailsZ chans_after_close2 = ChannelManager_list_channels(&cm2);
        assert(chans_after_close2->datalen == 0);
 
+       assert(OnionMessenger_send_custom_onion_message(&om1,
+                       LDKCVec_PublicKeyZ { .data = NULL, .datalen = 0, },
+                       Destination_node(ChannelManager_get_our_node_id(&cm2)),
+                       build_custom_onion_message(), LDKBlindedRoute { .inner = NULL, .is_owned = true })
+               .result_ok);
+       PeerManager_process_events(&net1);
+       while (true) {
+               std::this_thread::yield();
+               std::unique_lock<std::mutex> lck(peer_2_custom_onion_messages.mtx);
+               if (peer_2_custom_onion_messages.msgs.size() != 0) break;
+       }
+
        conn.stop();
 
+       std::unique_lock<std::mutex> lck(peer_2_custom_onion_messages.mtx);
+       assert(peer_2_custom_onion_messages.msgs.size() == 1);
+       assert(peer_2_custom_onion_messages.msgs[0].tlv_type() == 8888);
+       assert(peer_2_custom_messages.msgs.size() != 0);
+
        // Few extra random tests:
        LDKSecretKey sk;
        memset(&sk, 42, 32);
        LDKThirtyTwoBytes kdiv_params;
        memset(&kdiv_params, 43, 32);
-       LDK::InMemorySigner signer = InMemorySigner_new(sk, sk, sk, sk, sk, random_bytes, 42, kdiv_params);
+       LDK::InMemorySigner signer = InMemorySigner_new(sk, sk, sk, sk, sk, sk, random_bytes, 42, kdiv_params);
 }