package org.ldk;
import org.bitcoinj.core.*;
-import org.bitcoinj.core.Transaction;
import org.bitcoinj.script.Script;
import org.junit.jupiter.api.Test;
-import org.ldk.batteries.ChannelManagerConstructor;
import org.ldk.batteries.NioPeerHandler;
import org.ldk.enums.LDKNetwork;
import org.ldk.impl.bindings;
synchronized (monitors) {
assert monitors.put(Arrays.toString(funding_txo.get_txid()), monitor) == null;
}
- return new Result_NoneChannelMonitorUpdateErrZ.Result_NoneChannelMonitorUpdateErrZ_OK();
+ return Result_NoneChannelMonitorUpdateErrZ.constructor_ok();
}
public Result_NoneChannelMonitorUpdateErrZ update_channel(OutPoint funding_txo, ChannelMonitorUpdate update) {
Result_NoneMonitorUpdateErrorZ update_res = monitors.get(txid).update_monitor(update, tx_broadcaster, fee_estimator, logger);
assert update_res instanceof Result_NoneMonitorUpdateErrorZ.Result_NoneMonitorUpdateErrorZ_OK;
}
- return new Result_NoneChannelMonitorUpdateErrZ.Result_NoneChannelMonitorUpdateErrZ_OK();
+ return Result_NoneChannelMonitorUpdateErrZ.constructor_ok();
}
@Override
final Logger logger;
final FeeEstimator fee_estimator;
final BroadcasterInterface tx_broadcaster;
+ final KeysManager explicit_keys_manager;
final KeysInterface keys_interface;
final ChainMonitor chain_monitor;
final NetGraphMsgHandler router;
final HashMap<String, ChannelMonitor> monitors; // Wow I forgot just how terrible Java is - we can't put a byte array here.
byte[] node_id;
final LinkedList<byte[]> broadcast_set = new LinkedList<>();
+ GcCheck obj = new GcCheck();
private TwoTuple<OutPoint, byte[]> test_mon_roundtrip(ChannelMonitor mon) {
// Because get_funding_txo() returns an OutPoint in a tuple that is a reference to an OutPoint inside the
assert Arrays.equals(res.a.get_txid(), id.get_txid());
assert res.a.get_index() == id.get_index();
}
- return new Result_NoneChannelMonitorUpdateErrZ.Result_NoneChannelMonitorUpdateErrZ_OK();
+ return Result_NoneChannelMonitorUpdateErrZ.constructor_ok();
}
@Override
assert Arrays.equals(res.a.get_txid(), id.get_txid());
assert res.a.get_index() == id.get_index();
}
- return new Result_NoneChannelMonitorUpdateErrZ.Result_NoneChannelMonitorUpdateErrZ_OK();
+ return Result_NoneChannelMonitorUpdateErrZ.constructor_ok();
}
});
@Override public void register_tx(byte[] txid, byte[] script_pubkey) {
filter_additions.add(Arrays.toString(txid));
}
- @Override public void register_output(OutPoint outpoint, byte[] script_pubkey) {
- filter_additions.add(Arrays.toString(outpoint.get_txid()) + ":" + outpoint.get_index());
+ @Override public Option_C2Tuple_usizeTransactionZZ register_output(WatchedOutput output) {
+ filter_additions.add(Arrays.toString(output.get_outpoint().get_txid()) + ":" + output.get_outpoint().get_index());
+ return Option_C2Tuple_usizeTransactionZZ.constructor_none();
}
});
} else {
KeysManager keys = KeysManager.constructor_new(key_seed, System.currentTimeMillis() / 1000, (int) (System.currentTimeMillis() * 1000));
if (use_km_wrapper) {
this.keys_interface = manual_keysif(keys.as_KeysInterface());
+ this.explicit_keys_manager = null;
} else {
this.keys_interface = keys.as_KeysInterface();
+ this.explicit_keys_manager = keys;
}
this.router = NetGraphMsgHandler.constructor_new(new byte[32], null, logger);
}
}
Peer(byte seed) {
this(null, seed);
- this.chan_manager = ChannelManager.constructor_new(FeeEstimator.new_impl(confirmation_target -> 0), chain_watch, tx_broadcaster, logger, this.keys_interface, UserConfig.constructor_default(), LDKNetwork.LDKNetwork_Bitcoin, new byte[32], 1);
+ this.chan_manager = ChannelManager.constructor_new(FeeEstimator.new_impl(confirmation_target -> 0), chain_watch, tx_broadcaster, logger, this.keys_interface, UserConfig.constructor_default(), LDKNetwork.LDKNetwork_Bitcoin, new byte[32], 0);
this.node_id = chan_manager.get_our_node_id();
this.chan_manager_events = chan_manager.as_EventsProvider();
Object ptr_to;
Peer(Peer orig) {
this(null, orig.seed);
- if (!break_cross_peer_refs) {
- ChannelMonitor[] monitors = new ChannelMonitor[1];
- synchronized (monitors) {
- assert orig.monitors.size() == 1;
+ // TODO: Optionally test ChannelManagerConstructor
+ ChannelMonitor[] monitors = new ChannelMonitor[1];
+ synchronized (monitors) {
+ assert orig.monitors.size() == 1;
+ if (!break_cross_peer_refs) {
monitors[0] = orig.monitors.values().stream().iterator().next();
- }
- byte[] serialized = orig.chan_manager.write();
- Result_C2Tuple_BlockHashChannelManagerZDecodeErrorZ read_res =
- UtilMethods.constructor_BlockHashChannelManagerZ_read(serialized, this.keys_interface, this.fee_estimator, this.chain_watch, this.tx_broadcaster, this.logger, UserConfig.constructor_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.b;
- this.chain_watch.watch_channel(monitors[0].get_funding_txo().a, monitors[0]);
- } else {
- final ArrayList<byte[]> channel_monitors = new ArrayList();
- synchronized (monitors) {
- assert orig.monitors.size() == 1;
- channel_monitors.add(orig.monitors.values().stream().iterator().next().write());
- }
- byte[] serialized = orig.chan_manager.write();
- try {
- ChannelManagerConstructor constructed = new ChannelManagerConstructor(serialized, channel_monitors.toArray(new byte[1][]), this.keys_interface, this.fee_estimator, this.chain_watch, this.filter, this.tx_broadcaster, this.logger);
- this.chan_manager = constructed.channel_manager;
- constructed.chain_sync_completed();
- if (use_filter && !use_manual_watch) {
- // With a manual watch we don't actually use the filter object at all.
- assert this.filter_additions.containsAll(orig.filter_additions) &&
- orig.filter_additions.containsAll(this.filter_additions);
- }
- } catch (ChannelManagerConstructor.InvalidSerializedDataException e) {
- assert false;
+ } else {
+ byte[] serialized = orig.monitors.values().stream().iterator().next().write();
+ Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ res =
+ UtilMethods.constructor_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.b;
}
}
+ byte[] serialized = orig.chan_manager.write();
+ Result_C2Tuple_BlockHashChannelManagerZDecodeErrorZ read_res =
+ UtilMethods.constructor_BlockHashChannelManagerZ_read(serialized, this.keys_interface, this.fee_estimator, this.chain_watch, this.tx_broadcaster, this.logger, UserConfig.constructor_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.b;
+ this.chain_watch.watch_channel(monitors[0].get_funding_txo().a, monitors[0]);
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
TwoTuple<Long, byte[]>[] txn;
if (b.hasTransactions()) {
assert b.getTransactions().size() == 1;
- TwoTuple<Long, byte[]> txp = new TwoTuple<>((long) 1, b.getTransactions().get(0).bitcoinSerialize());
+ TwoTuple<Long, byte[]> txp = new TwoTuple<>((long) 0, b.getTransactions().get(0).bitcoinSerialize());
txn = new TwoTuple[]{txp};
} else
txn = new TwoTuple[0];
- chan_manager.block_connected(header, txn, height);
if (chain_monitor != null) {
+ chan_manager.as_Listen().block_connected(b.bitcoinSerialize(), height);
chain_monitor.block_connected(header, txn, height);
} else {
+ chan_manager.transactions_confirmed(header, height, txn);
+ chan_manager.update_best_block(header, height);
+ // Connect manually if we aren't using a ChainMonitor and are implementing Watch ourselves
synchronized (monitors) {
assert monitors.size() == 1;
for (ChannelMonitor mon : monitors.values()) {
Route get_route(byte[] dest_node, ChannelDetails[] our_chans) {
try (LockedNetworkGraph netgraph = this.router.read_locked_graph()) {
NetworkGraph graph = netgraph.graph();
- long res = bindings.get_route(this.node_id, graph._test_only_get_ptr(), dest_node, new long[]{our_chans[0]._test_only_get_ptr()},
- new long[0], 1000, 42, this.logger._test_only_get_ptr());
+ long res = bindings.get_route(this.node_id, graph._test_only_get_ptr(), dest_node, 0L, new long[]{our_chans[0]._test_only_get_ptr()},
+ new long[0], 1000000, 42, this.logger._test_only_get_ptr());
assert bindings.LDKCResult_RouteLightningErrorZ_result_ok(res);
byte[] serialized_route = bindings.Route_write(bindings.LDKCResult_RouteLightningErrorZ_get_ok(res));
must_free_objs.add(new WeakReference<>(serialized_route));
funding.getInputs().get(0).setWitness(new TransactionWitness(2)); // Make sure we don't complain about lack of witness
funding.getInput(0).getWitness().setPush(0, new byte[]{0x1});
funding.addOutput(Coin.SATOSHI.multiply(10000), new Script(funding_spk));
- peer1.chan_manager.funding_transaction_generated(chan_id, OutPoint.constructor_new(funding.getTxId().getReversedBytes(), (short) 0));
+ Result_NoneAPIErrorZ funding_res = peer1.chan_manager.funding_transaction_generated(chan_id, funding.bitcoinSerialize(), (short) 0);
+ assert funding_res instanceof Result_NoneAPIErrorZ.Result_NoneAPIErrorZ_OK;
wait_events_processed(peer1, peer2);
- events = peer1.chan_manager_events.get_and_clear_pending_events();
- assert events.length == 1;
- assert events[0] instanceof Event.FundingBroadcastSafe;
- assert ((Event.FundingBroadcastSafe) events[0]).user_channel_id == 42;
+ assert peer1.broadcast_set.size() == 1;
+ assert Arrays.equals(peer1.broadcast_set.get(0), funding.bitcoinSerialize());
+ peer1.broadcast_set.clear();
Block b = new Block(bitcoinj_net, 2, Sha256Hash.ZERO_HASH, Sha256Hash.ZERO_HASH, 42, 0, 0, Arrays.asList(new Transaction[]{funding}));
peer1.connect_block(b, 1, 0);
wait_events_processed(peer1, peer2);
peer1.chan_manager.list_channels();
- ChannelDetails[] peer1_chans = peer1.chan_manager.list_channels();
- ChannelDetails[] peer2_chans = peer2.chan_manager.list_channels();
+ ChannelDetails[] peer1_chans = peer1.chan_manager.list_usable_channels();
+ ChannelDetails[] peer2_chans = peer2.chan_manager.list_usable_channels();
assert peer1_chans.length == 1;
assert peer2_chans.length == 1;
assert peer1_chans[0].get_channel_value_satoshis() == 10000;
assert peer1_chans[0].get_is_live();
+ Option_u64Z short_chan_id = peer1_chans[0].get_short_channel_id();
+ assert short_chan_id instanceof Option_u64Z.Some;
+ assert ((Option_u64Z.Some)short_chan_id).some == (1L << 40); // 0th output in the 0th transaction in the 1st block
assert Arrays.equals(peer1_chans[0].get_channel_id(), funding.getTxId().getReversedBytes());
assert Arrays.equals(peer2_chans[0].get_channel_id(), funding.getTxId().getReversedBytes());
System.runFinalization();
}
connect_peers(state.peer1, state.peer2);
- wait_events_processed(state.peer1, state.peer2);
}
+ wait_events_processed(state.peer1, state.peer2);
Event[] events = state.peer2.chan_manager_events.get_and_clear_pending_events();
assert events.length == 1;
wait_events_processed(state.peer1, state.peer2);
assert state.peer1.broadcast_set.size() == 1;
- assert state.peer2.broadcast_set.size() == 0;
+ assert state.peer2.broadcast_set.size() == 1;
NetworkParameters bitcoinj_net = NetworkParameters.fromID(NetworkParameters.ID_MAINNET);
Transaction tx = new Transaction(bitcoinj_net, state.peer1.broadcast_set.getFirst());
Block b = new Block(bitcoinj_net, 2, state.best_blockhash, Sha256Hash.ZERO_HASH, 42, 0, 0,
Arrays.asList(new Transaction[]{tx}));
- TwoTuple<byte[], TwoTuple<Integer, TxOut>[]>[] watch_outputs = state.peer2.connect_block(b, 1, 1);
+ TwoTuple<byte[], TwoTuple<Integer, TxOut>[]>[] watch_outputs = state.peer2.connect_block(b, 10, 1);
if (watch_outputs != null) { // We only process watch_outputs manually when we use a manually-build Watch impl
assert watch_outputs.length == 1;
assert Arrays.equals(watch_outputs[0].a, tx.getTxId().getReversedBytes());
- assert watch_outputs[0].b.length == 1;
+ assert watch_outputs[0].b.length == 2;
+ assert watch_outputs[0].b[0].a == 0;
+ assert watch_outputs[0].b[1].a == 1;
+ }
+
+ for (int i = 11; i < 21; i++) {
+ b = new Block(bitcoinj_net, 2, b.getHash(), Sha256Hash.ZERO_HASH, 42, 0, 0, new ArrayList<>());
+ state.peer2.connect_block(b, i, 0);
}
+ Event[] broadcastable_event = null;
+ if (state.peer2.chain_monitor != null) {
+ broadcastable_event = state.peer2.chain_monitor.as_EventsProvider().get_and_clear_pending_events();
+ }
// This used to be buggy and double-free, so go ahead and fetch them!
for (ChannelMonitor mon : state.peer2.monitors.values()) {
byte[][] txn = mon.get_latest_holder_commitment_txn(state.peer2.logger);
+ if (state.peer2.chain_monitor == null) {
+ broadcastable_event = mon.get_and_clear_pending_events();
+ }
+ }
+ assert broadcastable_event.length == 1;
+ assert broadcastable_event[0] instanceof Event.SpendableOutputs;
+ if (state.peer2.explicit_keys_manager != null) {
+ Result_TransactionNoneZ tx_res = state.peer2.explicit_keys_manager.spend_spendable_outputs(((Event.SpendableOutputs) broadcastable_event[0]).outputs, new TxOut[0], new byte[] {0x00}, 253);
+ assert tx_res instanceof Result_TransactionNoneZ.Result_TransactionNoneZ_OK;
+ Transaction built_tx = new Transaction(bitcoinj_net, ((Result_TransactionNoneZ.Result_TransactionNoneZ_OK) tx_res).res);
+ assert built_tx.getOutputs().size() == 1;
+ assert Arrays.equals(built_tx.getOutput(0).getScriptBytes(), new byte[]{0x00});
}
}
}
java.util.LinkedList<WeakReference<Object>> must_free_objs = new java.util.LinkedList();
- boolean gc_ran = false;
+ int gc_count = 0;
+ int gc_exp_count = 0;
class GcCheck {
+ GcCheck() { gc_exp_count += 1; }
@Override
protected void finalize() throws Throwable {
- gc_ran = true;
+ gc_count += 1;
super.finalize();
}
}
}
void do_test(boolean nice_close, boolean use_km_wrapper, boolean use_manual_watch, boolean reload_peers, boolean break_cross_peer_refs, boolean nio_peer_handler) throws InterruptedException {
HumanObjectPeerTestInstance instance = do_test_run(nice_close, use_km_wrapper, use_manual_watch, reload_peers, break_cross_peer_refs, nio_peer_handler);
- while (!instance.gc_ran) {
+ while (instance.gc_count != instance.gc_exp_count) {
System.gc();
System.runFinalization();
}