X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=src%2Ftest%2Fjava%2Forg%2Fldk%2FHumanObjectPeerTest.java;h=58d707645fec969532c1daab1f2fdd85363d4f2e;hb=197962d9373b042e0d3434937db9ccf0360489ea;hp=b51df8429cb17c3c2befa3a1cceaa8d0ab33ed3f;hpb=a46cc8c472582d1b094f73ded7d691c4695bed0d;p=ldk-java diff --git a/src/test/java/org/ldk/HumanObjectPeerTest.java b/src/test/java/org/ldk/HumanObjectPeerTest.java index b51df842..58d70764 100644 --- a/src/test/java/org/ldk/HumanObjectPeerTest.java +++ b/src/test/java/org/ldk/HumanObjectPeerTest.java @@ -7,6 +7,7 @@ import org.ldk.batteries.ChannelManagerConstructor; import org.ldk.batteries.NioPeerHandler; import org.ldk.enums.AccessError; import org.ldk.enums.Currency; +import org.ldk.enums.Level; import org.ldk.enums.Network; import org.ldk.structs.*; import org.ldk.util.TwoTuple; @@ -189,19 +190,28 @@ class HumanObjectPeerTestInstance { InvoicePayer payer = null; GcCheck obj = new GcCheck(); - private TwoTuple_OutPointScriptZ test_mon_roundtrip(ChannelMonitor mon) { + private ChannelMonitor test_mon_roundtrip(OutPoint expected_id, byte[] data) { // Because get_funding_txo() returns an OutPoint in a tuple that is a reference to an OutPoint inside the // ChannelMonitor, its a good test to ensure that the OutPoint isn't freed (or is cloned) before the // ChannelMonitor is. This used to be broken. - Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ roundtrip_monitor = UtilMethods.C2Tuple_BlockHashChannelMonitorZ_read(mon.write(), keys_interface); + Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ roundtrip_monitor = UtilMethods.C2Tuple_BlockHashChannelMonitorZ_read(data, keys_interface); assert roundtrip_monitor instanceof Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ.Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ_OK; TwoTuple_OutPointScriptZ funding_txo = ((Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ.Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ_OK) roundtrip_monitor).res.get_b().get_funding_txo(); System.gc(); System.runFinalization(); // Give the GC a chance to run. - return funding_txo; + assert Arrays.equals(funding_txo.get_a().get_txid(), expected_id.get_txid()); + assert funding_txo.get_a().get_index() == expected_id.get_index(); + Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ roundtrip_two = UtilMethods.C2Tuple_BlockHashChannelMonitorZ_read(data, keys_interface); + assert roundtrip_two instanceof Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ.Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ_OK; + return ((Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ.Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ_OK) roundtrip_two).res.get_b(); } private Peer(Object _dummy, byte seed) { - logger = Logger.new_impl((String arg) -> System.out.println(seed + ": " + arg)); + logger = Logger.new_impl((Record arg)->{ + if (arg.get_level() == Level.LDKLevel_Error) + System.err.println(seed + ": " + arg.get_module_path() + " - " + arg.get_args()); + else + System.out.println(seed + ": " + arg.get_module_path() + " - " + arg.get_args()); + }); fee_estimator = FeeEstimator.new_impl((confirmation_target -> 253)); tx_broadcaster = BroadcasterInterface.new_impl(tx -> { synchronized (broadcast_set) { @@ -216,10 +226,8 @@ class HumanObjectPeerTestInstance { public Result_NoneChannelMonitorUpdateErrZ persist_new_channel(OutPoint id, ChannelMonitor data, MonitorUpdateId update_id) { synchronized (monitors) { String key = Arrays.toString(id.to_channel_id()); - assert monitors.put(key, data) == null; - TwoTuple_OutPointScriptZ res = test_mon_roundtrip(data); - assert Arrays.equals(res.get_a().get_txid(), id.get_txid()); - assert res.get_a().get_index() == id.get_index(); + ChannelMonitor res = test_mon_roundtrip(id, data.write()); + assert monitors.put(key, res) == null; } return Result_NoneChannelMonitorUpdateErrZ.ok(); } @@ -228,10 +236,10 @@ class HumanObjectPeerTestInstance { public Result_NoneChannelMonitorUpdateErrZ update_persisted_channel(OutPoint id, ChannelMonitorUpdate update, ChannelMonitor data, MonitorUpdateId update_id) { synchronized (monitors) { String key = Arrays.toString(id.to_channel_id()); - assert monitors.put(key, data) != null; - TwoTuple_OutPointScriptZ res = test_mon_roundtrip(data); - assert Arrays.equals(res.get_a().get_txid(), id.get_txid()); - assert res.get_a().get_index() == id.get_index(); + ChannelMonitor res = test_mon_roundtrip(id, data.write()); + // Note that we use a serialization-roundtrip copy of data here, not the original, as this can + // expose the JVM JIT bug where it finalize()s things still being called. + assert monitors.put(key, res) != null; } return Result_NoneChannelMonitorUpdateErrZ.ok(); } @@ -404,11 +412,23 @@ class HumanObjectPeerTestInstance { filter_nullable = ((Option_FilterZ.Some) this.filter).some; } if (use_ignore_handler) { - this.constructor = new ChannelManagerConstructor(serialized, monitors, this.keys_interface, - this.fee_estimator, this.chain_monitor, filter_nullable, null, this.tx_broadcaster, this.logger); + this.constructor = new ChannelManagerConstructor(serialized, monitors, UserConfig.with_default(), + this.keys_interface, this.fee_estimator, this.chain_monitor, filter_nullable, + null, this.tx_broadcaster, this.logger); } else { - this.constructor = new ChannelManagerConstructor(serialized, monitors, this.keys_interface, - this.fee_estimator, this.chain_monitor, filter_nullable, this.router, this.tx_broadcaster, this.logger); + this.constructor = new ChannelManagerConstructor(serialized, monitors, UserConfig.with_default(), + this.keys_interface, this.fee_estimator, this.chain_monitor, filter_nullable, + this.router, this.tx_broadcaster, this.logger); + try { + // Test that ChannelManagerConstructor correctly rejects duplicate ChannelMonitors + byte[][] monitors_dupd = new byte[2][]; + monitors_dupd[0] = monitors[0]; + monitors_dupd[1] = monitors[0]; + ChannelManagerConstructor constr = this.constructor = new ChannelManagerConstructor(serialized, monitors_dupd, UserConfig.with_default(), + this.keys_interface, this.fee_estimator, this.chain_monitor, filter_nullable, + null, this.tx_broadcaster, this.logger); + assert false; + } catch (ChannelManagerConstructor.InvalidSerializedDataException e) {} } LockableScore scorer = null; if (use_invoice_payer) { scorer = LockableScore.of(Scorer.with_default().as_Score()); } @@ -1023,6 +1043,8 @@ class HumanObjectPeerTestInstance { t.interrupt(); + state.peer1.router.write(); + // Construct the only Option_Enum::Variant(OpaqueStruct) we have in the codebase as this used to cause double-frees: 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,}; Result_ChannelUpdateDecodeErrorZ upd_msg = ChannelUpdate.read(serd); @@ -1060,6 +1082,14 @@ public class HumanObjectPeerTest { } @Test public void test_message_handler() throws InterruptedException { + Thread gc_thread = new Thread(() -> { + while (true) { + System.gc(); + System.runFinalization(); + try { Thread.sleep(0, 1); } catch (InterruptedException e) { break; } + } + }, "Test GC Thread"); + gc_thread.start(); for (int i = 0; i < (1 << 9) - 1; i++) { boolean nice_close = (i & (1 << 0)) != 0; boolean use_km_wrapper = (i & (1 << 1)) != 0; @@ -1092,6 +1122,8 @@ public class HumanObjectPeerTest { System.err.println("Running test with flags " + i); do_test(nice_close, use_km_wrapper, use_manual_watch, reload_peers, break_cross_refs, nio_peer_handler, use_ignoring_routing_handler, use_chan_manager_constructor, use_invoice_payer); } + gc_thread.interrupt(); + gc_thread.join(); } // This is used in the test jar to test the built jar is runnable