@@ -176,8 +176,12 @@ public MonitorEvent[] release_pending_monitor_events() {
176176 PeerManager peer_manager ;
177177 final HashMap <String , ChannelMonitor > monitors ; // Wow I forgot just how terrible Java is - we can't put a byte array here.
178178 byte [] node_id ;
179+ byte [] connected_peer_node_id = null ;
179180 final LinkedList <byte []> broadcast_set = new LinkedList <>();
180181 final LinkedList <Event > pending_manager_events = new LinkedList <>();
182+ private final CustomMessageHandler custom_message_handler ;
183+ final LinkedList <byte []> received_custom_messages = new LinkedList <>();
184+ final LinkedList <byte []> custom_messages_to_send = new LinkedList <>();
181185 ChannelManagerConstructor constructor = null ;
182186 GcCheck obj = new GcCheck ();
183187
@@ -264,7 +268,52 @@ public Result_NoneChannelMonitorUpdateErrZ update_persisted_channel(OutPoint id,
264268 this .keys_interface = keys .as_KeysInterface ();
265269 this .explicit_keys_manager = keys ;
266270 }
267- this .router = NetGraphMsgHandler .of (new byte [32 ], Option_AccessZ .none (), logger );
271+ this .router = NetGraphMsgHandler .of (new byte [32 ], Option_AccessZ .some (Access .new_impl (new Access .AccessInterface () {
272+ @ Override
273+ public Result_TxOutAccessErrorZ get_utxo (byte [] genesis_hash , long short_channel_id ) {
274+ // We don't exchange any gossip, so should never actually get called, but providing a Some(Access)
275+ // is a good test of our Option<Trait> free'ing, which used to be broken and relies on a dirty hack.
276+ assert false ;
277+ return Result_TxOutAccessErrorZ .err (AccessError .LDKAccessError_UnknownTx );
278+ }
279+ })), logger );
280+
281+ this .custom_message_handler = CustomMessageHandler .new_impl (new CustomMessageHandler .CustomMessageHandlerInterface () {
282+ @ Override
283+ public Result_NoneLightningErrorZ handle_custom_message (Type msg , byte [] sender_node_id ) {
284+ synchronized (received_custom_messages ) {
285+ received_custom_messages .add (msg .write ());
286+ received_custom_messages .notifyAll ();
287+ }
288+ return Result_NoneLightningErrorZ .ok ();
289+ }
290+
291+ @ Override
292+ public TwoTuple <byte [], Type >[] get_and_clear_pending_msg () {
293+ byte [][] bytes ;
294+ synchronized (custom_messages_to_send ) {
295+ bytes = custom_messages_to_send .toArray (new byte [0 ][0 ]);
296+ custom_messages_to_send .clear ();
297+ }
298+ TwoTuple [] ret = new TwoTuple [bytes .length ];
299+ for (int i = 0 ; i < bytes .length ; i ++) {
300+ final int msg_idx = i ;
301+ ret [i ] = new TwoTuple (connected_peer_node_id , Type .new_impl (new Type .TypeInterface () {
302+ @ Override public short type_id () { return 4096 ; }
303+ @ Override public String debug_str () { return "Custom Java Message" ; }
304+ @ Override public byte [] write () { return bytes [msg_idx ]; }
305+ }));
306+ }
307+ return ret ;
308+ }
309+ }, (message_type , buffer ) -> {
310+ assert message_type == 4096 ;
311+ return Result_COption_TypeZDecodeErrorZ .ok (Option_TypeZ .some (Type .new_impl (new Type .TypeInterface () {
312+ @ Override public short type_id () { return 4096 ; }
313+ @ Override public String debug_str () { return "Custom Java-Decoded Message" ; }
314+ @ Override public byte [] write () { return buffer ; }
315+ })));
316+ });
268317 }
269318 private void bind_nio () {
270319 if (!use_nio_peer_handler ) return ;
@@ -306,7 +355,7 @@ private void bind_nio() {
306355 ChainParameters params = ChainParameters .of (Network .LDKNetwork_Bitcoin , BestBlock .of (new byte [32 ], 0 ));
307356 this .chan_manager = ChannelManager .of (this .fee_estimator , chain_watch , tx_broadcaster , logger , this .keys_interface , UserConfig .with_default (), params );
308357 byte [] random_data = keys_interface .get_secure_random_bytes ();
309- this .peer_manager = PeerManager .of (chan_manager .as_ChannelMessageHandler (), router .as_RoutingMessageHandler (), keys_interface .get_node_secret (), random_data , logger , IgnoringMessageHandler . of (). as_CustomMessageHandler () );
358+ this .peer_manager = PeerManager .of (chan_manager .as_ChannelMessageHandler (), router .as_RoutingMessageHandler (), keys_interface .get_node_secret (), random_data , logger , this . custom_message_handler );
310359 }
311360
312361 this .node_id = chan_manager .get_our_node_id ();
@@ -368,7 +417,7 @@ private void bind_nio() {
368417 this .chan_manager = ((Result_C2Tuple_BlockHashChannelManagerZDecodeErrorZ .Result_C2Tuple_BlockHashChannelManagerZDecodeErrorZ_OK ) read_res ).res .b ;
369418 this .chain_watch .watch_channel (monitors [0 ].get_funding_txo ().a , monitors [0 ]);
370419 byte [] random_data = keys_interface .get_secure_random_bytes ();
371- this .peer_manager = PeerManager .of (chan_manager .as_ChannelMessageHandler (), router .as_RoutingMessageHandler (), keys_interface .get_node_secret (), random_data , logger , IgnoringMessageHandler . of (). as_CustomMessageHandler () );
420+ this .peer_manager = PeerManager .of (chan_manager .as_ChannelMessageHandler (), router .as_RoutingMessageHandler (), keys_interface .get_node_secret (), random_data , logger , this . custom_message_handler );
372421 if (!break_cross_peer_refs && (use_manual_watch || use_km_wrapper )) {
373422 // When we pass monitors[0] into chain_watch.watch_channel we create a reference from the new Peer to a
374423 // field in the old peer, preventing freeing of the original Peer until the new Peer is freed. Thus, we
@@ -557,6 +606,8 @@ void do_read_event(PeerManager pm, SocketDescriptor descriptor, byte[] data) {
557606 }
558607
559608 void connect_peers (final Peer peer1 , final Peer peer2 ) {
609+ peer2 .connected_peer_node_id = peer1 .node_id ;
610+ peer1 .connected_peer_node_id = peer2 .node_id ;
560611 if (use_nio_peer_handler ) {
561612 try {
562613 peer1 .nio_peer_handler .connect (peer2 .chan_manager .get_our_node_id (), new InetSocketAddress ("127.0.0.1" , peer2 .nio_port ), 100 );
@@ -693,6 +744,9 @@ TestState do_test_message_handler() throws InterruptedException {
693744 Result_RouteLightningErrorZ route_res = UtilMethods .get_route (peer1 .chan_manager .get_our_node_id (), peer1 .router .get_network_graph (), peer2 .node_id , invoice_features , peer1_chans , route_hints , 10000000 , 42 , peer1 .logger );
694745 assert route_res instanceof Result_RouteLightningErrorZ .Result_RouteLightningErrorZ_OK ;
695746 Route route = ((Result_RouteLightningErrorZ .Result_RouteLightningErrorZ_OK ) route_res ).res ;
747+ assert route .get_paths ().length == 1 ;
748+ assert route .get_paths ()[0 ].length == 1 ;
749+ assert route .get_paths ()[0 ][0 ].get_fee_msat () == 10000000 ;
696750
697751 Result_NonePaymentSendFailureZ payment_res = peer1 .chan_manager .send_payment (route , payment_hash , payment_secret );
698752 assert payment_res instanceof Result_NonePaymentSendFailureZ .Result_NonePaymentSendFailureZ_OK ;
@@ -824,8 +878,8 @@ void do_test_message_handler_b(TestState state) throws InterruptedException {
824878 assert broadcastable_event .length == 1 ;
825879 assert broadcastable_event [0 ] instanceof Event .SpendableOutputs ;
826880 if (state .peer2 .explicit_keys_manager != null ) {
827- TxOut [] additional_outputs = new TxOut [] { new TxOut (420 , new byte [] { 0x42 }) };
828- Result_TransactionNoneZ tx_res = state .peer2 .explicit_keys_manager .spend_spendable_outputs (((Event .SpendableOutputs ) broadcastable_event [0 ]).outputs , additional_outputs , new byte [] {0x00 }, 253 );
881+ TxOut [] additional_outputs = new TxOut []{ new TxOut (420 , new byte []{ 0x42 }) };
882+ Result_TransactionNoneZ tx_res = state .peer2 .explicit_keys_manager .spend_spendable_outputs (((Event .SpendableOutputs ) broadcastable_event [0 ]).outputs , additional_outputs , new byte []{0x00 }, 253 );
829883 assert tx_res instanceof Result_TransactionNoneZ .Result_TransactionNoneZ_OK ;
830884 Transaction built_tx = new Transaction (bitcoinj_net , ((Result_TransactionNoneZ .Result_TransactionNoneZ_OK ) tx_res ).res );
831885 assert built_tx .getOutputs ().size () == 2 ;
@@ -835,6 +889,22 @@ void do_test_message_handler_b(TestState state) throws InterruptedException {
835889 }
836890 }
837891
892+ // Test exchanging a custom message
893+ byte [] custom_message_bytes = new byte [] { 0x42 , 0x44 , 0x43 , 0x00 };
894+ state .peer1 .custom_messages_to_send .add (custom_message_bytes );
895+ state .peer1 .peer_manager .process_events ();
896+ synchronized (state .peer2 .received_custom_messages ) {
897+ while (true ) {
898+ if (state .peer2 .received_custom_messages .isEmpty ()) {
899+ state .peer2 .received_custom_messages .wait ();
900+ continue ;
901+ }
902+ assert state .peer2 .received_custom_messages .size () == 1 ;
903+ assert Arrays .equals (state .peer2 .received_custom_messages .get (0 ), custom_message_bytes );
904+ break ;
905+ }
906+ }
907+
838908 if (use_nio_peer_handler ) {
839909 state .peer1 .peer_manager .disconnect_by_node_id (state .peer2 .chan_manager .get_our_node_id (), false );
840910 while (state .peer1 .peer_manager .get_peer_node_ids ().length != 0 ) Thread .yield ();
@@ -852,6 +922,12 @@ void do_test_message_handler_b(TestState state) throws InterruptedException {
852922 }
853923
854924 t .interrupt ();
925+
926+ // Construct the only Option_Enum::Variant(OpaqueStruct) we have in the codebase as this used to cause double-frees:
927+ byte [] serd = new byte [] {(byte )0xd9 ,(byte )0x77 ,(byte )0xcb ,(byte )0x9b ,(byte )0x53 ,(byte )0xd9 ,(byte )0x3a ,(byte )0x6f ,(byte )0xf6 ,(byte )0x4b ,(byte )0xb5 ,(byte )0xf1 ,(byte )0xe1 ,(byte )0x58 ,(byte )0xb4 ,(byte )0x09 ,(byte )0x4b ,(byte )0x66 ,(byte )0xe7 ,(byte )0x98 ,(byte )0xfb ,(byte )0x12 ,(byte )0x91 ,(byte )0x11 ,(byte )0x68 ,(byte )0xa3 ,(byte )0xcc ,(byte )0xdf ,(byte )0x80 ,(byte )0xa8 ,(byte )0x30 ,(byte )0x96 ,(byte )0x34 ,(byte )0x0a ,(byte )0x6a ,(byte )0x95 ,(byte )0xda ,(byte )0x0a ,(byte )0xe8 ,(byte )0xd9 ,(byte )0xf7 ,(byte )0x76 ,(byte )0x52 ,(byte )0x8e ,(byte )0xec ,(byte )0xdb ,(byte )0xb7 ,(byte )0x47 ,(byte )0xeb ,(byte )0x6b ,(byte )0x54 ,(byte )0x54 ,(byte )0x95 ,(byte )0xa4 ,(byte )0x31 ,(byte )0x9e ,(byte )0xd5 ,(byte )0x37 ,(byte )0x8e ,(byte )0x35 ,(byte )0xb2 ,(byte )0x1e ,(byte )0x07 ,(byte )0x3a ,(byte )0x00 ,(byte )0x00 ,(byte )0x00 ,(byte )0x00 ,(byte )0x00 ,(byte )0x19 ,(byte )0xd6 ,(byte )0x68 ,(byte )0x9c ,(byte )0x08 ,(byte )0x5a ,(byte )0xe1 ,(byte )0x65 ,(byte )0x83 ,(byte )0x1e ,(byte )0x93 ,(byte )0x4f ,(byte )0xf7 ,(byte )0x63 ,(byte )0xae ,(byte )0x46 ,(byte )0xa2 ,(byte )0xa6 ,(byte )0xc1 ,(byte )0x72 ,(byte )0xb3 ,(byte )0xf1 ,(byte )0xb6 ,(byte )0x0a ,(byte )0x8c ,(byte )0xe2 ,(byte )0x6f ,(byte )0x00 ,(byte )0x08 ,(byte )0x3a ,(byte )0x84 ,(byte )0x00 ,(byte )0x00 ,(byte )0x03 ,(byte )0x4d ,(byte )0x01 ,(byte )0x34 ,(byte )0x13 ,(byte )0xa7 ,(byte )0x00 ,(byte )0x00 ,(byte )0x00 ,(byte )0x90 ,(byte )0x00 ,(byte )0x00 ,(byte )0x00 ,(byte )0x00 ,(byte )0x00 ,(byte )0x0f ,(byte )0x42 ,(byte )0x40 ,(byte )0x00 ,(byte )0x00 ,(byte )0x27 ,(byte )0x10 ,(byte )0x00 ,(byte )0x00 ,(byte )0x00 ,(byte )0x14 ,};
928+ Result_ChannelUpdateDecodeErrorZ upd_msg = ChannelUpdate .read (serd );
929+ assert upd_msg instanceof Result_ChannelUpdateDecodeErrorZ .Result_ChannelUpdateDecodeErrorZ_OK ;
930+ Option_NetworkUpdateZ upd = Option_NetworkUpdateZ .some (NetworkUpdate .channel_update_message (((Result_ChannelUpdateDecodeErrorZ .Result_ChannelUpdateDecodeErrorZ_OK ) upd_msg ).res ));
855931 }
856932
857933 java .util .LinkedList <WeakReference <Object >> must_free_objs = new java .util .LinkedList ();
0 commit comments