Skip to content

Commit d2925e2

Browse files
authored
Merge pull request #69 from TheBlueMatt/main
v0.0.104.0
2 parents 6d094e7 + 7da8cb1 commit d2925e2

File tree

381 files changed

+13694
-3465
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

381 files changed

+13694
-3465
lines changed

.github/workflows/build.yml

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ jobs:
3535
cd ..
3636
git clone https://github.com/lightningdevkit/ldk-c-bindings
3737
cd ldk-c-bindings
38-
git checkout 0.0.103
38+
git checkout 0.0.104
3939
- name: Rebuild C bindings without STD for WASM
4040
run: |
4141
cd ldk-c-bindings
@@ -161,7 +161,7 @@ jobs:
161161
cd ..
162162
git clone https://github.com/lightningdevkit/ldk-c-bindings
163163
cd ldk-c-bindings
164-
git checkout 0.0.103
164+
git checkout 0.0.104
165165
- name: Checkout Android AAR binaries and artifacts
166166
run: |
167167
# Gitweb only allows snapshots of folders by providing the object hash, which we have to extract:
@@ -243,7 +243,7 @@ jobs:
243243
cd ..
244244
git clone https://github.com/lightningdevkit/ldk-c-bindings
245245
cd ldk-c-bindings
246-
git checkout 0.0.103
246+
git checkout 0.0.104
247247
- name: Rebuild C bindings with upstream clang, and check the sample app builds + links
248248
run: |
249249
cd ldk-c-bindings
@@ -258,8 +258,6 @@ jobs:
258258
exit 1
259259
fi
260260
tar xvvf openjdk-16.0.1_osx-x64_bin.tar.gz
261-
export JAVA_HOME=`pwd`/jdk-16.0.1.jdk/Contents/Home
262-
export PATH=$JAVA_HOME/bin:$PATH
263261
- name: Checkout latest Linux binaries
264262
run: |
265263
export LDK_GARBAGECOLLECTED_GIT_OVERRIDE="$(git describe --tag HEAD)"
@@ -277,6 +275,8 @@ jobs:
277275
- name: Build Java/TS Release Bindings
278276
run: |
279277
export LDK_GARBAGECOLLECTED_GIT_OVERRIDE="$(git describe --tag HEAD)"
278+
export JAVA_HOME=`pwd`/jdk-16.0.1.jdk/Contents/Home
279+
export PATH=$JAVA_HOME/bin:$PATH
280280
# genbindings.sh always fails as there is no wasm32-wasi library
281281
# available, so instead we check that the expected JNI library
282282
# is created.
@@ -304,7 +304,9 @@ jobs:
304304
export PATH=apache-maven-3.8.4/bin:$PATH
305305
- name: Run Java Tests against built jar
306306
run: |
307-
mvn -q -B -DskipTests=true package
307+
export JAVA_HOME=`pwd`/jdk-16.0.1.jdk/Contents/Home
308+
export PATH=$JAVA_HOME/bin:$PATH
309+
mvn -DskipTests=true package
308310
export LDK_GARBAGECOLLECTED_GIT_OVERRIDE="$(git describe --tag HEAD)"
309311
JAR_VERSION=${LDK_GARBAGECOLLECTED_GIT_OVERRIDE:1:100}
310312
mvn install:install-file -Dfile=target/ldk-java-${JAR_VERSION}.jar -DgroupId=org.lightningdevkit -DartifactId=ldk-java -Dversion=1.0-SNAPSHOT -Dpackaging=jar
@@ -324,6 +326,8 @@ jobs:
324326
run: |
325327
if [ "${{ matrix.platform }}" != "macos-11" ]; then
326328
export LDK_GARBAGECOLLECTED_GIT_OVERRIDE="$(git describe --tag HEAD)"
329+
export JAVA_HOME=`pwd`/jdk-16.0.1.jdk/Contents/Home
330+
export PATH=$JAVA_HOME/bin:$PATH
327331
cp "ldk-java-bins/${LDK_GARBAGECOLLECTED_GIT_OVERRIDE}/"liblightningjni_MacOSX-{x86_64,aarch64}.nativelib src/main/resources/
328332
mvn clean
329333
mvn -q -B -DskipTests=true package

android-build.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ for IDX in ${!EXTRA_TARGETS[@]}; do
4949
${STRIPS[$IDX]} liblightningjni_release_${LDK_TARGET}.so
5050
done
5151

52-
export LANG=C
52+
export LC_ALL=C
5353

5454
echo "Need local deterministic ldk-java-classes.jar"
5555
ls ldk-java-classes.jar

build-release-jar.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ ls src/main/resources/liblightningjni_Linux-amd64.nativelib
99
ls src/main/resources/liblightningjni_MacOSX-x86_64.nativelib
1010
ls src/main/resources/liblightningjni_MacOSX-aarch64.nativelib
1111

12-
export LANG=C
12+
export LC_ALL=C
1313

1414
# We need to fetch dependencies first as faketime will break PKI cert checks!
1515
mvn -DskipTests=true -Dorg.lightningdevkit.skipdocs=false package

genbindings.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,10 @@ def java_c_types(fn_arg, ret_arr_len):
174174
assert var_is_arr_regex.match(fn_arg[8:])
175175
rust_obj = "LDKTwentyBytes"
176176
arr_access = "data"
177-
elif fn_arg.startswith("LDKTenBytes"):
178-
fn_arg = "uint8_t (*" + fn_arg[12:] + ")[10]"
177+
elif fn_arg.startswith("LDKTwelveBytes"):
178+
fn_arg = "uint8_t (*" + fn_arg[15:] + ")[12]"
179179
assert var_is_arr_regex.match(fn_arg[8:])
180-
rust_obj = "LDKTenBytes"
180+
rust_obj = "LDKTwelveBytes"
181181
arr_access = "data"
182182
elif fn_arg.startswith("LDKu8slice"):
183183
fn_arg = "uint8_t (*" + fn_arg[11:] + ")[datalen]"

java_strings.py

Lines changed: 72 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ def __init__(self, DEBUG: bool, target: Target, **kwargs):
106106
import org.ldk.enums.*;
107107
import org.ldk.util.*;
108108
import java.util.Arrays;
109+
import java.lang.ref.Reference;
109110
import javax.annotation.Nullable;
110111
111112
public class UtilMethods {
@@ -129,6 +130,9 @@ class CommonBase {
129130
#include <stdatomic.h>
130131
#include <stdlib.h>
131132
133+
#define LIKELY(v) __builtin_expect(!!(v), 1)
134+
#define UNLIKELY(v) __builtin_expect(!!(v), 0)
135+
132136
"""
133137

134138
if self.target == Target.ANDROID:
@@ -512,6 +516,7 @@ class CommonBase {
512516
import org.ldk.enums.*;
513517
import org.ldk.util.*;
514518
import java.util.Arrays;
519+
import java.lang.ref.Reference;
515520
import javax.annotation.Nullable;
516521
517522
"""
@@ -616,8 +621,13 @@ def native_c_unitary_enum_map(self, struct_name, variants, enum_doc_comment):
616621
out_java_enum = "package org.ldk.enums;\n\n"
617622
out_java = ""
618623
out_c = ""
619-
out_c = out_c + "static inline LDK" + struct_name + " LDK" + struct_name + "_from_java(" + self.c_fn_args_pfx + ") {\n"
620-
out_c = out_c + "\tswitch ((*env)->CallIntMethod(env, clz, ordinal_meth)) {\n"
624+
out_c += "static inline LDK" + struct_name + " LDK" + struct_name + "_from_java(" + self.c_fn_args_pfx + ") {\n"
625+
out_c += "\tjint ord = (*env)->CallIntMethod(env, clz, ordinal_meth);\n"
626+
out_c += "\tif (UNLIKELY((*env)->ExceptionCheck(env))) {\n"
627+
out_c += "\t\t(*env)->ExceptionDescribe(env);\n"
628+
out_c += "\t\t(*env)->FatalError(env, \"A call to " + struct_name + ".ordinal() from rust threw an exception.\");\n"
629+
out_c += "\t}\n"
630+
out_c += "\tswitch (ord) {\n"
621631

622632
if enum_doc_comment is not None:
623633
out_java_enum += "/**\n * " + enum_doc_comment.replace("\n", "\n * ") + "\n */\n"
@@ -633,9 +643,10 @@ def native_c_unitary_enum_map(self, struct_name, variants, enum_doc_comment):
633643
out_java_enum = out_java_enum + "\tstatic { init(); }\n"
634644
out_java_enum = out_java_enum + "}"
635645
out_java = out_java + "\tstatic { " + struct_name + ".values(); /* Force enum statics to run */ }\n"
636-
out_c = out_c + "\t}\n"
637-
out_c = out_c + "\tabort();\n"
638-
out_c = out_c + "}\n"
646+
out_c += "\t}\n"
647+
out_c += "\t(*env)->FatalError(env, \"A call to " + struct_name + ".ordinal() from rust returned an invalid value.\");\n"
648+
out_c += "\tabort(); // Unreachable, but will let the compiler know we don't return here\n"
649+
out_c += "}\n"
639650

640651
out_c = out_c + "static jclass " + struct_name + "_class = NULL;\n"
641652
for var, _ in variants:
@@ -672,14 +683,11 @@ def c_complex_enum_pfx(self, struct_name, variants, init_meth_jty_strs):
672683
out_c = out_c + "static jmethodID " + struct_name + "_" + var + "_meth = NULL;\n"
673684
out_c = out_c + self.c_fn_ty_pfx + "void JNICALL Java_org_ldk_impl_bindings_00024" + struct_name.replace("_", "_1") + "_init (" + self.c_fn_args_pfx + ") {\n"
674685
for var_name in variants:
675-
out_c = out_c + "\t" + struct_name + "_" + var_name + "_class =\n"
676-
if self.target == Target.ANDROID:
677-
out_c = out_c + "\t\t(*env)->NewGlobalRef(env, (*env)->FindClass(env, \"org/ldk/impl/bindings$" + struct_name + "$" + var_name + "\"));\n"
678-
else:
679-
out_c = out_c + "\t\t(*env)->NewGlobalRef(env, (*env)->FindClass(env, \"Lorg/ldk/impl/bindings$" + struct_name + "$" + var_name + ";\"));\n"
680-
out_c = out_c + "\tCHECK(" + struct_name + "_" + var_name + "_class != NULL);\n"
681-
out_c = out_c + "\t" + struct_name + "_" + var_name + "_meth = (*env)->GetMethodID(env, " + struct_name + "_" + var_name + "_class, \"<init>\", \"(" + init_meth_jty_strs[var_name] + ")V\");\n"
682-
out_c = out_c + "\tCHECK(" + struct_name + "_" + var_name + "_meth != NULL);\n"
686+
out_c += "\t" + struct_name + "_" + var_name + "_class =\n"
687+
out_c += "\t\t(*env)->NewGlobalRef(env, (*env)->FindClass(env, \"org/ldk/impl/bindings$" + struct_name + "$" + var_name + "\"));\n"
688+
out_c += "\tCHECK(" + struct_name + "_" + var_name + "_class != NULL);\n"
689+
out_c += "\t" + struct_name + "_" + var_name + "_meth = (*env)->GetMethodID(env, " + struct_name + "_" + var_name + "_class, \"<init>\", \"(" + init_meth_jty_strs[var_name] + ")V\");\n"
690+
out_c += "\tCHECK(" + struct_name + "_" + var_name + "_meth != NULL);\n"
683691
out_c = out_c + "}\n"
684692
return out_c
685693

@@ -901,7 +909,7 @@ def native_c_map_trait(self, struct_name, field_vars, flattened_field_vars, fiel
901909
out_c = out_c + ", " + arg_info.arg_name
902910
out_c = out_c + ");\n"
903911

904-
out_c += "\tif ((*env)->ExceptionCheck(env)) {\n"
912+
out_c += "\tif (UNLIKELY((*env)->ExceptionCheck(env))) {\n"
905913
out_c += "\t\t(*env)->ExceptionDescribe(env);\n"
906914
out_c += "\t\t(*env)->FatalError(env, \"A call to " + fn_line.fn_name + " in " + struct_name + " from rust threw an exception.\");\n"
907915
out_c += "\t}\n"
@@ -1187,6 +1195,7 @@ def map_function(self, argument_types, c_call_string, method_name, meth_n, retur
11871195
out_java += (arg_conv_info.java_ty + " " + arg_conv_info.arg_name)
11881196

11891197
out_java_struct = ""
1198+
extra_java_struct_out = ""
11901199
if not args_known:
11911200
out_java_struct += ("\t// Skipped " + method_name + "\n")
11921201
else:
@@ -1204,6 +1213,15 @@ def map_function(self, argument_types, c_call_string, method_name, meth_n, retur
12041213
elif meth_n == "clone_ptr":
12051214
out_java_struct += ("\t" + return_type_info.java_hu_ty + " " + meth_n + "(")
12061215
else:
1216+
if meth_n == "hash" and return_type_info.java_hu_ty == "long":
1217+
extra_java_struct_out = "\t@Override public int hashCode() {\n"
1218+
extra_java_struct_out += "\t\treturn (int)this.hash();\n"
1219+
extra_java_struct_out += "\t}\n"
1220+
elif meth_n == "eq" and return_type_info.java_hu_ty == "boolean":
1221+
extra_java_struct_out = "\t@Override public boolean equals(Object o) {\n"
1222+
extra_java_struct_out += "\t\tif (!(o instanceof " + struct_meth + ")) return false;\n"
1223+
extra_java_struct_out += "\t\treturn this.eq((" + struct_meth + ")o);\n"
1224+
extra_java_struct_out += "\t}\n"
12071225
out_java_struct += ("\tpublic " + return_type_info.java_hu_ty + " " + meth_n + "(")
12081226
for idx, arg in enumerate(argument_types):
12091227
if idx != 0:
@@ -1291,6 +1309,45 @@ def map_function(self, argument_types, c_call_string, method_name, meth_n, retur
12911309
else:
12921310
out_java_struct += (info.arg_name)
12931311
out_java_struct += (");\n")
1312+
1313+
# This is completely nuts. The OpenJDK JRE JIT will optimize out a object which is on
1314+
# the stack, calling its finalizer immediately even if member methods are *actively
1315+
# executing* on the same object, as long as said object is on the stack. There is no
1316+
# concrete specification for when the optimizer is allowed to do this, and when it is
1317+
# not, so there is absolutely no way to be certain that this fix suffices.
1318+
#
1319+
# Instead, the "Java Language Specification" says only that an object is reachable
1320+
# (i.e. will not yet be finalized) if it "can be accessed in any potential continuing
1321+
# computation from any live thread". To any sensible reader this would mean actively
1322+
# executing a member function on an object would make it not eligible for finalization.
1323+
# But, no, dear reader, this statement does not say that. Well, okay, it says that,
1324+
# very explicitly in fact, but those are just, like, words, man.
1325+
#
1326+
# In the seemingly non-normative text further down, a few examples of things the
1327+
# optimizer can do are given, including "if the values in an object's fields are
1328+
# stored in registers[, t]he may then access the registers instead of the object, and
1329+
# never access the object again[, implying] that the object is garbage". This appears
1330+
# to fully contradict both the above statement, the API documentation in java.lang.ref
1331+
# regarding when a reference is "strongly reachable", and basic common sense. There is
1332+
# no concrete set of limitations stated, however, seemingly implying the JIT could
1333+
# decide your code would run faster by simply garbage collecting everything
1334+
# immediately, ensuring your code finishes soon, just by SEGFAULT. Thus, we're really
1335+
# entirely flying blind here. We add some fences and hope that its sufficient, but
1336+
# with no specification to rely on, we cannot be certain of anything.
1337+
#
1338+
# TL;DR: The Java Language "Specification" provides no real guarantees on when an
1339+
# object will be considered available for garbage collection once the JIT kicks in, so
1340+
# we put in some fences and hope to god the JIT doesn't get smarter/more broken.
1341+
for idx, info in enumerate(argument_types):
1342+
if idx == 0 and takes_self:
1343+
out_java_struct += ("\t\tReference.reachabilityFence(this);\n")
1344+
elif info.arg_name in default_constructor_args:
1345+
for explode_idx, explode_arg in enumerate(default_constructor_args[info.arg_name]):
1346+
expl_arg_name = info.arg_name + "_" + explode_arg.arg_name
1347+
out_java_struct += ("\t\tReference.reachabilityFence(" + expl_arg_name + ");\n")
1348+
elif info.c_ty != "void":
1349+
out_java_struct += ("\t\tReference.reachabilityFence(" + info.arg_name + ");\n")
1350+
12941351
if return_type_info.java_ty == "long" and return_type_info.java_hu_ty != "long":
12951352
out_java_struct += "\t\tif (ret >= 0 && ret <= 4096) { return null; }\n"
12961353

@@ -1326,4 +1383,4 @@ def map_function(self, argument_types, c_call_string, method_name, meth_n, retur
13261383
out_java_struct += ("\t\treturn ret;\n")
13271384
out_java_struct += ("\t}\n\n")
13281385

1329-
return (out_java, out_c, out_java_struct)
1386+
return (out_java, out_c, out_java_struct + extra_java_struct_out)

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@
6363
</dependency>
6464
</dependencies>
6565
<properties>
66-
<maven.compiler.source>1.8</maven.compiler.source>
67-
<maven.compiler.target>1.8</maven.compiler.target>
66+
<maven.compiler.source>9</maven.compiler.source>
67+
<maven.compiler.target>9</maven.compiler.target>
6868
<org.lightningdevkit.skipdocs>true</org.lightningdevkit.skipdocs>
6969
</properties>
7070

src/main/java/org/ldk/batteries/ChannelManagerConstructor.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import org.ldk.util.TwoTuple;
77

88
import java.io.IOException;
9+
import java.util.HashSet;
910

1011

1112
/**
@@ -19,7 +20,11 @@ public class ChannelManagerConstructor {
1920
* An Exception that indicates the serialized data is invalid and has been corrupted on disk. You should attempt to
2021
* restore from a backup if there is one which is known to be current. Otherwise, funds may have been lost.
2122
*/
22-
public static class InvalidSerializedDataException extends Exception {}
23+
public static class InvalidSerializedDataException extends Exception {
24+
InvalidSerializedDataException(String reason) {
25+
super(reason);
26+
}
27+
}
2328

2429
/**
2530
* The ChannelManager either deserialized or newly-constructed.
@@ -75,20 +80,23 @@ public ChannelManagerConstructor(byte[] channel_manager_serialized, byte[][] cha
7580
final IgnoringMessageHandler no_custom_messages = IgnoringMessageHandler.of();
7681
final ChannelMonitor[] monitors = new ChannelMonitor[channel_monitors_serialized.length];
7782
this.channel_monitors = new TwoTuple_BlockHashChannelMonitorZ[monitors.length];
83+
HashSet<OutPoint> monitor_funding_set = new HashSet();
7884
for (int i = 0; i < monitors.length; i++) {
7985
Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ res = UtilMethods.C2Tuple_BlockHashChannelMonitorZ_read(channel_monitors_serialized[i], keys_interface);
8086
if (res instanceof Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ.Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ_Err) {
81-
throw new InvalidSerializedDataException();
87+
throw new InvalidSerializedDataException("Serialized ChannelMonitor was corrupt");
8288
}
8389
byte[] block_hash = ((Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ.Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ_OK)res).res.get_a();
8490
monitors[i] = ((Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ.Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ_OK) res).res.get_b();
8591
this.channel_monitors[i] = TwoTuple_BlockHashChannelMonitorZ.of(block_hash, monitors[i]);
92+
if (!monitor_funding_set.add(monitors[i].get_funding_txo().get_a()))
93+
throw new InvalidSerializedDataException("Set of ChannelMonitors contained duplicates (ie the same funding_txo was set on multiple monitors)");
8694
}
8795
Result_C2Tuple_BlockHashChannelManagerZDecodeErrorZ res =
8896
UtilMethods.C2Tuple_BlockHashChannelManagerZ_read(channel_manager_serialized, keys_interface, fee_estimator, chain_monitor.as_Watch(), tx_broadcaster,
8997
logger, config, monitors);
9098
if (res instanceof Result_C2Tuple_BlockHashChannelManagerZDecodeErrorZ.Result_C2Tuple_BlockHashChannelManagerZDecodeErrorZ_Err) {
91-
throw new InvalidSerializedDataException();
99+
throw new InvalidSerializedDataException("Serialized ChannelManager was corrupt");
92100
}
93101
this.channel_manager = ((Result_C2Tuple_BlockHashChannelManagerZDecodeErrorZ.Result_C2Tuple_BlockHashChannelManagerZDecodeErrorZ_OK)res).res.get_b();
94102
this.channel_manager_latest_block_hash = ((Result_C2Tuple_BlockHashChannelManagerZDecodeErrorZ.Result_C2Tuple_BlockHashChannelManagerZDecodeErrorZ_OK)res).res.get_a();
@@ -176,7 +184,7 @@ public interface EventHandler {
176184
* This also spawns a background thread which will call the appropriate methods on the provided
177185
* EventHandler as required.
178186
*/
179-
public void chain_sync_completed(EventHandler event_handler, @Nullable LockableScore scorer) {
187+
public void chain_sync_completed(EventHandler event_handler, @Nullable MultiThreadedLockableScore scorer) {
180188
if (background_processor != null) { return; }
181189
for (TwoTuple_BlockHashChannelMonitorZ monitor: channel_monitors) {
182190
this.chain_monitor.as_Watch().watch_channel(monitor.get_b().get_funding_txo().get_a(), monitor.get_b());

src/main/java/org/ldk/batteries/NioPeerHandler.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import java.io.IOException;
77
import java.lang.reflect.Field;
8+
import java.lang.ref.Reference;
89
import java.util.LinkedList;
910
import java.net.SocketAddress;
1011
import java.net.StandardSocketOptions;
@@ -339,6 +340,7 @@ public void interrupt() {
339340
}
340341
} catch (IOException ignored) {}
341342
}
343+
Reference.reachabilityFence(this.peer_manager); // Almost certainly overkill, but no harm in it
342344
}
343345

344346
/**
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.ldk.enums;
2+
3+
/**
4+
* An enum which can either contain a or not
5+
*/
6+
public enum COption_NoneZ {
7+
/**
8+
* When we're in this state, this COption_NoneZ contains a
9+
*/
10+
LDKCOption_NoneZ_Some,
11+
/**
12+
* When we're in this state, this COption_NoneZ contains nothing
13+
*/
14+
LDKCOption_NoneZ_None,
15+
; static native void init();
16+
static { init(); }
17+
}

src/main/java/org/ldk/enums/CreationError.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ public enum CreationError {
2020
* The supplied expiry time could cause an overflow if added to a `PositiveTimestamp`
2121
*/
2222
LDKCreationError_ExpiryTimeOutOfBounds,
23+
/**
24+
* The supplied millisatoshi amount was greater than the total bitcoin supply.
25+
*/
26+
LDKCreationError_InvalidAmount,
2327
; static native void init();
2428
static { init(); }
2529
}

0 commit comments

Comments
 (0)