+ Object ptr_to;
+ Peer(Peer orig) {
+ this(null, orig.seed);
+ if (use_chan_manager_constructor) {
+ byte[][] monitors = {orig.monitors.values().stream().iterator().next().write()};
+ byte[] serialized = orig.chan_manager.write();
+ try {
+ Filter filter_nullable = null;
+ if (this.filter instanceof Option_FilterZ.Some) {
+ filter_nullable = ((Option_FilterZ.Some) this.filter).some;
+ }
+ if (use_ignore_handler) {
+ 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, UserConfig.with_default(),
+ this.keys_interface, this.fee_estimator, this.chain_monitor, filter_nullable,
+ this.router, this.tx_broadcaster, this.logger);
+ }
+ LockableScore scorer = null;
+ if (use_invoice_payer) { scorer = LockableScore.of(Scorer.with_default().as_Score()); }
+ constructor.chain_sync_completed(new ChannelManagerConstructor.EventHandler() {
+ @Override public void handle_event(Event event) {
+ synchronized (pending_manager_events) {
+ pending_manager_events.add(event);
+ pending_manager_events.notifyAll();
+ }
+ }
+ @Override public void persist_manager(byte[] channel_manager_bytes) { assert channel_manager_bytes.length > 1; }
+ }, scorer);
+ this.chan_manager = constructor.channel_manager;
+ this.payer = constructor.payer;
+ this.peer_manager = constructor.peer_manager;
+ must_free_objs.add(new WeakReference<>(this.chan_manager));
+ // If we are using a ChannelManagerConstructor, we may have pending events waiting on the old peer
+ // which have been removed from the ChannelManager but which we still need to handle.
+ this.pending_manager_events.addAll(orig.pending_manager_events);
+ if (!this.pending_manager_events.isEmpty()) {
+ // However, this implies cross_reload_ref_pollution
+ cross_reload_ref_pollution = true;
+ }
+ } catch (ChannelManagerConstructor.InvalidSerializedDataException e) {
+ assert false;
+ }
+ } else {
+ ChannelMonitor[] monitors = new ChannelMonitor[1];
+ assert orig.monitors.size() == 1;
+ if (!break_cross_peer_refs) {
+ monitors[0] = orig.monitors.values().stream().iterator().next();
+ } else {
+ byte[] serialized = orig.monitors.values().stream().iterator().next().write();
+ Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ res =
+ UtilMethods.C2Tuple_BlockHashChannelMonitorZ_read(serialized, this.keys_interface);
+ assert res instanceof Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ.Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ_OK;
+ monitors[0] = ((Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ.Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ_OK) res).res.get_b();
+ }
+ byte[] serialized = orig.chan_manager.write();
+ Result_C2Tuple_BlockHashChannelManagerZDecodeErrorZ read_res =
+ UtilMethods.C2Tuple_BlockHashChannelManagerZ_read(serialized, this.keys_interface, this.fee_estimator, this.chain_watch, this.tx_broadcaster, this.logger, UserConfig.with_default(), monitors);
+ assert read_res instanceof Result_C2Tuple_BlockHashChannelManagerZDecodeErrorZ.Result_C2Tuple_BlockHashChannelManagerZDecodeErrorZ_OK;
+ this.chan_manager = ((Result_C2Tuple_BlockHashChannelManagerZDecodeErrorZ.Result_C2Tuple_BlockHashChannelManagerZDecodeErrorZ_OK) read_res).res.get_b();
+ this.chain_watch.watch_channel(monitors[0].get_funding_txo().get_a(), monitors[0]);
+ byte[] random_data = keys_interface.get_secure_random_bytes();
+ this.peer_manager = PeerManager.of(chan_manager.as_ChannelMessageHandler(), route_handler.as_RoutingMessageHandler(), keys_interface.get_node_secret(), random_data, logger, this.custom_message_handler);
+ if (!break_cross_peer_refs && (use_manual_watch || use_km_wrapper)) {
+ // When we pass monitors[0] into chain_watch.watch_channel we create a reference from the new Peer to a
+ // field in the old peer, preventing freeing of the original Peer until the new Peer is freed. Thus, we
+ // shouldn't bother waiting for the original to be freed later on.
+ cross_reload_ref_pollution = true;
+ }
+ if (use_invoice_payer) {
+ this.payer = InvoicePayer.of(this.chan_manager.as_Payer(), Router.new_impl(new Router.RouterInterface() {
+ @Override
+ public Result_RouteLightningErrorZ find_route(byte[] payer, RouteParameters params, ChannelDetails[] first_hops, Score scorer) {
+ return UtilMethods.find_route(payer, params, router, first_hops, logger, scorer);
+ }
+ }), LockableScore.of(Score.new_impl(new Score.ScoreInterface() {
+ @Override public void payment_path_failed(RouteHop[] path, long scid) {}
+ @Override public long channel_penalty_msat(long scid, NodeId src, NodeId dst) { return 0; }
+ @Override public byte[] write() { assert false; return null; }
+ })), logger, EventHandler.new_impl(new EventHandler.EventHandlerInterface() {
+ @Override public void handle_event(Event event) {
+ synchronized (pending_manager_events) {
+ pending_manager_events.add(event);
+ pending_manager_events.notifyAll();
+ }
+ }
+ }), RetryAttempts.of(0));
+ }
+ }
+ this.node_id = chan_manager.get_our_node_id();
+ bind_nio();
+
+ if (cross_reload_ref_pollution) {
+ // This really, really needs to be handled at the bindings layer, but its rather complicated -
+ // ChannelSigners can be cloned and passed around without java being involved, resulting in them being
+ // owned by both one or more ChannelMonitors and a ChannelManager, with only one having proper pointers
+ // to the ChannelSigner. Ideally, the ChannelSigner would have a global reference to the Java
+ // implementation class, but that results in circular references. Instead, we need some ability to,
+ // while cloning ChannelSigners, add new references in the calling Java struct (ie ChannelMonitor) to
+ // the ChannelSigner.
+ this.ptr_to = orig.chan_manager;
+ }
+ this.filter = null;
+ }
+
+ TwoTuple_TxidCVec_C2Tuple_u32TxOutZZZ[] connect_block(Block b, int height, long expected_monitor_update_len) {