X-Git-Url: http://git.bitcoin.ninja/index.cgi?p=ldk-c-bindings;a=blobdiff_plain;f=lightning-c-bindings%2Fdemo.cpp;h=7c6dfda2e0f1c93ffbe83ba0a7dfbc9c0943ff53;hp=4bc3115e9715295ce96d1ffa0cf1f3b372d6120e;hb=a82e075188fc15a103234832686915c196bfe240;hpb=51a702cc824ac8c0d280cf695ddaade7142d84fa diff --git a/lightning-c-bindings/demo.cpp b/lightning-c-bindings/demo.cpp index 4bc3115..7c6dfda 100644 --- a/lightning-c-bindings/demo.cpp +++ b/lightning-c-bindings/demo.cpp @@ -1,11 +1,17 @@ extern "C" { #include + +#ifdef REAL_NET +#include +#endif } #include "include/lightningpp.hpp" #include #include #include +#include +#include #include #include @@ -185,6 +191,77 @@ LDKCVec_MonitorEventZ monitors_pending_monitor_events(const void *this_arg) { } } +struct EventQueue { + std::vector events; +}; +void handle_event(const void *this_arg, LDKEvent event) { + EventQueue* arg = (EventQueue*) this_arg; + arg->events.push_back(std::move(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(); + } + + // 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); } @@ -231,7 +308,7 @@ public: .disconnect_socket = sock_disconnect_socket, .eq = sock_eq, .hash = sock_hash, - .clone = NULL, + .cloned = NULL, .free = NULL, }; @@ -241,7 +318,7 @@ public: .disconnect_socket = sock_disconnect_socket, .eq = sock_eq, .hash = sock_hash, - .clone = NULL, + .cloned = NULL, .free = NULL, }; @@ -275,6 +352,7 @@ public: t2.join(); } }; +#endif // !REAL_NET int main() { uint8_t channel_open_header[80]; @@ -403,14 +481,16 @@ int main() { 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; } @@ -419,16 +499,18 @@ 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_block + 58 + 81, 34)); + 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(channel_open_block + 81), .datalen = sizeof(channel_open_block) - 81, .data_is_owned = false }; - LDK::CResult_NoneAPIErrorZ fund_res = ChannelManager_funding_transaction_generated(&cm1, &events->data[0].funding_generation_ready.temporary_channel_id.data, funding_transaction); + 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; } @@ -475,38 +557,53 @@ int main() { 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)); break; } std::this_thread::yield(); } - LDK::CVec_ChannelDetailsZ outbound_channels = ChannelManager_list_usable_channels(&cm1); LDKCOption_u64Z min_value = { .tag = LDKCOption_u64Z_Some, .some = 5000, }; - LDK::C2Tuple_PaymentHashPaymentSecretZ payment_hash_secret = ChannelManager_create_inbound_payment(&cm2, min_value, 3600, 43); + 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::CVec_ChannelDetailsZ outbound_channels = ChannelManager_list_usable_channels(&cm1); 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), LDKInvoiceFeatures { .inner = NULL, .is_owned = false - }, &outbound_channels, LDKCVec_RouteHintHopZ { - .data = NULL, .datalen = 0 - }, 5000, 10, logger1); + }, &outbound_channels, Invoice_route_hints(invoice->contents.result), + 5000, Invoice_min_final_cltv_expiry(invoice->contents.result), logger1); assert(route->result_ok); - LDK::CResult_NonePaymentSendFailureZ send_res = ChannelManager_send_payment(&cm1, route->contents.result, payment_hash_secret->a, payment_hash_secret->b); + LDK::CResult_NonePaymentSendFailureZ send_res = ChannelManager_send_payment(&cm1, route->contents.result, payment_hash, Invoice_payment_secret(invoice->contents.result)); assert(send_res->result_ok); } @@ -519,9 +616,11 @@ int main() { // Check that we received the payment! LDKEventsProvider 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(ev2.this_arg, handler); + if (queue.events.size() == 1) { + assert(queue.events[0]->tag == LDKEvent_PendingHTLCsForwardable); break; } std::this_thread::yield(); @@ -532,13 +631,17 @@ int main() { 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_secret->a.data, 32)); - assert(!memcmp(events->data[0].payment_received.payment_secret.data, payment_hash_secret->b.data, 32)); - assert(events->data[0].payment_received.amt == 5000); - memcpy(payment_preimage.data, events->data[0].payment_received.payment_preimage.data, 32); + EventQueue queue; + LDKEventHandler handler = { .this_arg = &queue, .handle_event = handle_event, .free = NULL }; + ev2.process_pending_events(ev2.this_arg, 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).data, 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); @@ -547,10 +650,12 @@ 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.data, 32)); + EventQueue queue; + LDKEventHandler handler = { .this_arg = &queue, .handle_event = handle_event, .free = NULL }; + ev1.process_pending_events(ev1.this_arg, handler); + assert(queue.events.size() == 1); + assert(queue.events[0]->tag == LDKEvent_PaymentSent); + assert(!memcmp(queue.events[0]->payment_sent.payment_preimage.data, payment_preimage.data, 32)); } conn.stop(); @@ -613,10 +718,10 @@ int main() { } // 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(); }