extern "C" {
#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>
}
}
+struct EventQueue {
+ std::vector<LDK::Event> 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);
}
.disconnect_socket = sock_disconnect_socket,
.eq = sock_eq,
.hash = sock_hash,
- .clone = NULL,
+ .cloned = NULL,
.free = NULL,
};
.disconnect_socket = sock_disconnect_socket,
.eq = sock_eq,
.hash = sock_hash,
- .clone = NULL,
+ .cloned = NULL,
.free = NULL,
};
t2.join();
}
};
+#endif // !REAL_NET
int main() {
uint8_t channel_open_header[80];
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;
}
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<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, &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;
}
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);
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::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);
+ 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);
}
// 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();
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);
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();
}
// 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();
}