From 8ce0ca412929b53499fece65584c7ec065a1972f Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Tue, 1 Sep 2020 15:25:53 -0400 Subject: [PATCH] Convert unitary enums to Java enums --- genbindings.py | 130 ++++++-- src/main/java/org/ldk/impl/bindings.java | 56 +++- src/main/jni/bindings.c | 279 ++++++++++++++++-- src/main/jni/org_ldk_impl_bindings.h | 36 ++- .../org/ldk/ManualMsgHandlingPeerTest.java | 3 + 5 files changed, 436 insertions(+), 68 deletions(-) diff --git a/genbindings.py b/genbindings.py index ab68ec81..78bb2ad8 100755 --- a/genbindings.py +++ b/genbindings.py @@ -46,6 +46,7 @@ class ConvInfo: with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java, open(sys.argv[3], "w") as out_c: opaque_structs = set() trait_structs = set() + unitary_enums = set() var_is_arr_regex = re.compile("\(\*([A-za-z_]*)\)\[([0-9]*)\]") var_ty_regex = re.compile("([A-za-z_0-9]*)(.*)") @@ -98,12 +99,20 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java, open(sys.arg fn_arg = fn_arg[6:].strip() else: ma = var_ty_regex.match(fn_arg) - java_ty = "long" - c_ty = "jlong" - fn_ty_arg = "J" - fn_arg = ma.group(2).strip() - rust_obj = ma.group(1).strip() - take_by_ptr = True + if ma.group(1).strip() in unitary_enums: + java_ty = ma.group(1).strip() + c_ty = "jclass" + fn_ty_arg = "Lorg/ldk/impl/bindings$" + ma.group(1).strip() + ";" + fn_arg = ma.group(2).strip() + rust_obj = ma.group(1).strip() + take_by_ptr = True + else: + java_ty = "long" + c_ty = "jlong" + fn_ty_arg = "J" + fn_arg = ma.group(2).strip() + rust_obj = ma.group(1).strip() + take_by_ptr = True if fn_arg.startswith(" *") or fn_arg.startswith("*"): fn_arg = fn_arg.replace("*", "").strip() @@ -153,6 +162,12 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java, open(sys.arg if ty_info.rust_obj is not None: assert(ty_info.passed_as_ptr) if not ty_info.is_ptr: + if ty_info.rust_obj in unitary_enums: + return ConvInfo(ty_info = ty_info, arg_name = ty_info.var_name, + arg_conv = ty_info.rust_obj + " " + ty_info.var_name + "_conv = " + ty_info.rust_obj + "_from_java(_env, " + ty_info.var_name + ");", + arg_conv_name = ty_info.var_name + "_conv", + ret_conv = ("jclass " + ty_info.var_name + "_conv = " + ty_info.rust_obj + "_to_java(_env, ", ");"), + ret_conv_name = ty_info.var_name + "_conv") base_conv = ty_info.rust_obj + " " + ty_info.var_name + "_conv = *(" + ty_info.rust_obj + "*)" + ty_info.var_name + ";"; if ty_info.rust_obj in trait_structs: if not is_free: @@ -205,6 +220,11 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java, open(sys.arg # We don't have a parameter name, and don't want one (cause we're returning) if ty_info.rust_obj is not None: if not ty_info.is_ptr: + if ty_info.rust_obj in unitary_enums: + return ConvInfo(ty_info = ty_info, arg_name = ty_info.var_name, + arg_conv = ty_info.rust_obj + " ret = " + ty_info.rust_obj + "_from_java(_env, " + ty_info.var_name + ");", + arg_conv_name = "ret", + ret_conv = ("jclass ret = " + ty_info.rust_obj + "_to_java(_env, ", ");"), ret_conv_name = "ret") if ty_info.rust_obj in opaque_structs: # If we're returning a newly-allocated struct, we don't want Rust to ever # free, instead relying on the Java GC to lose the ref. We undo this in @@ -425,8 +445,10 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java, open(sys.arg out_java.write("""package org.ldk.impl; public class bindings { + static native void init(java.lang.Class c); static { System.loadLibrary(\"lightningjni\"); + init(java.lang.Enum.class); } """) @@ -436,6 +458,13 @@ public class bindings { out_c.write("#include \n") out_c.write("#include \n") out_c.write("#include \n\n") + + out_c.write("jmethodID ordinal_meth = NULL;\n") + out_c.write("JNIEXPORT void Java_org_ldk_impl_bindings_init(JNIEnv * env, jclass _b, jclass enum_class) {\n") + out_c.write("\tordinal_meth = (*env)->GetMethodID(env, enum_class, \"ordinal\", \"()I\");\n") + out_c.write("\tassert(ordinal_meth != NULL);\n") + out_c.write("}\n\n") + if sys.argv[4] == "false": out_c.write("#define MALLOC(a, _) malloc(a)\n") out_c.write("#define FREE free\n\n") @@ -486,9 +515,7 @@ public class bindings { out_c.write("}\n") # TODO: rm me in_block_comment = False - in_block_enum = False - cur_block_struct = None - in_block_union = False + cur_block_obj = None fn_ptr_regex = re.compile("^extern const ([A-Za-z_0-9\* ]*) \(\*(.*)\)\((.*)\);$") fn_ret_arr_regex = re.compile("(.*) \(\*(.*)\((.*)\)\)\[([0-9]*)\];$") @@ -502,7 +529,7 @@ public class bindings { assert(line_indicates_trait_regex.match(" void *(*clone)(const void *this_arg);")) line_field_var_regex = re.compile("^ ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$") assert(line_field_var_regex.match(" LDKMessageSendEventsProvider MessageSendEventsProvider;")) - struct_name_regex = re.compile("^typedef (struct|enum) (MUST_USE_STRUCT )?(LDK[A-Za-z_0-9]*) {$") + struct_name_regex = re.compile("^typedef (struct|enum|union) (MUST_USE_STRUCT )?(LDK[A-Za-z_0-9]*) {$") assert(struct_name_regex.match("typedef struct LDKCVecTempl_u8 {")) assert(struct_name_regex.match("typedef enum LDKNetwork {")) @@ -511,17 +538,20 @@ public class bindings { #out_java.write("\t" + line) if line.endswith("*/\n"): in_block_comment = False - elif cur_block_struct is not None: - cur_block_struct = cur_block_struct + line + elif cur_block_obj is not None: + cur_block_obj = cur_block_obj + line if line.startswith("} "): field_lines = [] struct_name = None - struct_lines = cur_block_struct.split("\n") + obj_lines = cur_block_obj.split("\n") is_opaque = False + is_unitary_enum = False + is_union_enum = False + is_union = False trait_fn_lines = [] field_var_lines = [] - for idx, struct_line in enumerate(struct_lines): + for idx, struct_line in enumerate(obj_lines): if struct_line.strip().startswith("/*"): in_block_comment = True if in_block_comment: @@ -530,7 +560,14 @@ public class bindings { else: struct_name_match = struct_name_regex.match(struct_line) if struct_name_match is not None: - struct_name = struct_name_match.group(2) + struct_name = struct_name_match.group(3) + if struct_name_match.group(1) == "enum": + if not struct_name.endswith("_Tag"): + is_unitary_enum = True + else: + is_union_enum = True + elif struct_name_match.group(1) == "union": + is_union = True if line_indicates_opaque_regex.match(struct_line): is_opaque = True trait_fn_match = line_indicates_trait_regex.match(struct_line) @@ -542,20 +579,57 @@ public class bindings { field_lines.append(struct_line) assert(struct_name is not None) - assert(len(trait_fn_lines) == 0 or not is_opaque) + assert(len(trait_fn_lines) == 0 or not (is_opaque or is_unitary_enum or is_union_enum or is_union)) + assert(not is_opaque or not (len(trait_fn_lines) != 0 or is_unitary_enum or is_union_enum or is_union)) + assert(not is_unitary_enum or not (len(trait_fn_lines) != 0 or is_opaque or is_union_enum or is_union)) + assert(not is_union_enum or not (len(trait_fn_lines) != 0 or is_unitary_enum or is_opaque or is_union)) + assert(not is_union or not (len(trait_fn_lines) != 0 or is_unitary_enum or is_union_enum or is_opaque)) if is_opaque: opaque_structs.add(struct_name) - if len(trait_fn_lines) > 0: + elif is_unitary_enum: + unitary_enums.add(struct_name) + out_c.write("static inline " + struct_name + " " + struct_name + "_from_java(JNIEnv *env, jclass val) {\n") + out_c.write("\tswitch ((*env)->CallIntMethod(env, val, ordinal_meth)) {\n") + ord_v = 0 + for idx, struct_line in enumerate(field_lines): + if idx == 0: + out_java.write("\tpublic enum " + struct_name + " {\n") + elif idx == len(field_lines) - 3: + assert(struct_line.endswith("_Sentinel,")) + elif idx == len(field_lines) - 2: + out_java.write("\t}\n") + elif idx == len(field_lines) - 1: + assert(struct_line == "") + else: + out_java.write("\t" + struct_line + "\n") + out_c.write("\t\tcase %d: return %s;\n" % (ord_v, struct_line.strip().strip(","))) + ord_v = ord_v + 1 + out_c.write("\t}\n") + out_c.write("\tassert(false);\n") + out_c.write("}\n") + + ord_v = 0 + out_c.write("static inline jclass " + struct_name + "_to_java(JNIEnv *env, " + struct_name + " val) {\n") + out_c.write("\t// TODO: This is pretty inefficient, we really need to cache the field IDs and class\n") + out_c.write("\tjclass enum_class = (*env)->FindClass(env, \"Lorg/ldk/impl/bindings$" + struct_name + ";\");\n") + out_c.write("\tassert(enum_class != NULL);\n") + out_c.write("\tswitch (val) {\n") + for idx, struct_line in enumerate(field_lines): + if idx > 0 and idx < len(field_lines) - 3: + variant = struct_line.strip().strip(",") + out_c.write("\t\tcase " + variant + ": {\n") + out_c.write("\t\t\tjfieldID field = (*env)->GetStaticFieldID(env, enum_class, \"" + variant + "\", \"Lorg/ldk/impl/bindings$" + struct_name + ";\");\n") + out_c.write("\t\t\tassert(field != NULL);\n") + out_c.write("\t\t\treturn (*env)->GetStaticObjectField(env, enum_class, field);\n") + out_c.write("\t\t}\n") + ord_v = ord_v + 1 + out_c.write("\t\tdefault: assert(false);\n") + out_c.write("\t}\n") + out_c.write("}\n\n") + elif len(trait_fn_lines) > 0: trait_structs.add(struct_name) map_trait(struct_name, field_var_lines, trait_fn_lines) - #out_java.write("/* " + "\n".join(field_lines) + "*/\n") - cur_block_struct = None - elif in_block_union: - if line.startswith("} "): - in_block_union = False - elif in_block_enum: - if line.startswith("} "): - in_block_enum = False + cur_block_obj = None else: fn_ptr = fn_ptr_regex.match(line) fn_ret_arr = fn_ret_arr_regex.match(line) @@ -569,11 +643,11 @@ public class bindings { if not line.endswith("*/\n"): in_block_comment = True elif line.startswith("typedef enum "): - in_block_enum = True + cur_block_obj = line elif line.startswith("typedef struct "): - cur_block_struct = line + cur_block_obj = line elif line.startswith("typedef union "): - in_block_union = True + cur_block_obj = line elif line.startswith("typedef "): pass elif fn_ptr is not None: diff --git a/src/main/java/org/ldk/impl/bindings.java b/src/main/java/org/ldk/impl/bindings.java index 947468c3..b89d336c 100644 --- a/src/main/java/org/ldk/impl/bindings.java +++ b/src/main/java/org/ldk/impl/bindings.java @@ -1,12 +1,52 @@ package org.ldk.impl; public class bindings { + static native void init(java.lang.Class c); static { System.loadLibrary("lightningjni"); + init(java.lang.Enum.class); } public static native long LDKSecretKey_new(); + public enum LDKChainError { + LDKChainError_NotSupported, + LDKChainError_NotWatched, + LDKChainError_UnknownTx, + } + public enum LDKChannelMonitorUpdateErr { + LDKChannelMonitorUpdateErr_TemporaryFailure, + LDKChannelMonitorUpdateErr_PermanentFailure, + } + public enum LDKConfirmationTarget { + LDKConfirmationTarget_Background, + LDKConfirmationTarget_Normal, + LDKConfirmationTarget_HighPriority, + } + public enum LDKLevel { + LDKLevel_Off, + LDKLevel_Error, + LDKLevel_Warn, + LDKLevel_Info, + LDKLevel_Debug, + LDKLevel_Trace, + } + public enum LDKNetwork { + LDKNetwork_Bitcoin, + LDKNetwork_Testnet, + LDKNetwork_Regtest, + } + public enum LDKSecp256k1Error { + LDKSecp256k1Error_IncorrectSignature, + LDKSecp256k1Error_InvalidMessage, + LDKSecp256k1Error_InvalidPublicKey, + LDKSecp256k1Error_InvalidSignature, + LDKSecp256k1Error_InvalidSecretKey, + LDKSecp256k1Error_InvalidRecoveryId, + LDKSecp256k1Error_InvalidTweak, + LDKSecp256k1Error_NotEnoughMemory, + LDKSecp256k1Error_CallbackPanicked, + } public interface LDKMessageSendEventsProvider { long get_and_clear_pending_msg_events(); } @@ -38,7 +78,7 @@ public class bindings { } public static native long LDKChainListener_new(LDKChainListener impl); public interface LDKFeeEstimator { - int get_est_sat_per_1000_weight(long confirmation_target); + int get_est_sat_per_1000_weight(LDKConfirmationTarget confirmation_target); } public static native long LDKFeeEstimator_new(LDKFeeEstimator impl); public interface LDKChannelKeys { @@ -123,7 +163,7 @@ public class bindings { /// extern const void (*C3Tuple_ChannelAnnouncementChannelUpdateChannelUpdateZ_free)(LDKC3Tuple_ChannelAnnouncementChannelUpdateChannelUpdateZ); public static native void C3Tuple_ChannelAnnouncementChannelUpdateChannelUpdateZ_free(long arg); /// extern const LDKCResult_C2Tuple_Scriptu64ZChainErrorZ (*CResult_C2Tuple_Scriptu64ZChainErrorZ_err)(LDKChainError); - public static native long CResult_C2Tuple_Scriptu64ZChainErrorZ_err(long arg); + public static native long CResult_C2Tuple_Scriptu64ZChainErrorZ_err(LDKChainError arg); /// extern const void (*CResult_C2Tuple_Scriptu64ZChainErrorZ_free)(LDKCResult_C2Tuple_Scriptu64ZChainErrorZ); public static native void CResult_C2Tuple_Scriptu64ZChainErrorZ_free(long arg); /// extern const LDKCResult_C2Tuple_Scriptu64ZChainErrorZ (*CResult_C2Tuple_Scriptu64ZChainErrorZ_ok)(LDKC2Tuple_Scriptu64Z); @@ -147,7 +187,7 @@ public class bindings { /// extern const void (*CResult_NoneAPIErrorZ_free)(LDKCResult_NoneAPIErrorZ); public static native void CResult_NoneAPIErrorZ_free(long arg); /// extern const LDKCResult_NoneChannelMonitorUpdateErrZ (*CResult_NoneChannelMonitorUpdateErrZ_err)(LDKChannelMonitorUpdateErr); - public static native long CResult_NoneChannelMonitorUpdateErrZ_err(long arg); + public static native long CResult_NoneChannelMonitorUpdateErrZ_err(LDKChannelMonitorUpdateErr arg); /// extern const void (*CResult_NoneChannelMonitorUpdateErrZ_free)(LDKCResult_NoneChannelMonitorUpdateErrZ); public static native void CResult_NoneChannelMonitorUpdateErrZ_free(long arg); /// extern const LDKCResult_NoneMonitorUpdateErrorZ (*CResult_NoneMonitorUpdateErrorZ_err)(LDKMonitorUpdateError); @@ -173,7 +213,7 @@ public class bindings { /// extern const LDKCResult_SignatureNoneZ (*CResult_SignatureNoneZ_ok)(LDKSignature); public static native long CResult_SignatureNoneZ_ok(long arg); /// extern const LDKCResult_TxCreationKeysSecpErrorZ (*CResult_TxCreationKeysSecpErrorZ_err)(LDKSecp256k1Error); - public static native long CResult_TxCreationKeysSecpErrorZ_err(long arg); + public static native long CResult_TxCreationKeysSecpErrorZ_err(LDKSecp256k1Error arg); /// extern const void (*CResult_TxCreationKeysSecpErrorZ_free)(LDKCResult_TxCreationKeysSecpErrorZ); public static native void CResult_TxCreationKeysSecpErrorZ_free(long arg); /// extern const LDKCResult_TxCreationKeysSecpErrorZ (*CResult_TxCreationKeysSecpErrorZ_ok)(LDKTxCreationKeys); @@ -281,7 +321,7 @@ public class bindings { /// void APIError_free(LDKAPIError this_ptr); public static native void APIError_free(long this_ptr); /// MUST_USE_RES LDKLevel Level_max(void); - public static native long Level_max(); + public static native LDKLevel Level_max(); /// void Logger_free(LDKLogger this_ptr); public static native void Logger_free(long this_ptr); /// void ChannelHandshakeConfig_free(LDKChannelHandshakeConfig this_ptr); @@ -425,7 +465,7 @@ public class bindings { /// LDKChainWatchInterface ChainWatchInterfaceUtil_as_ChainWatchInterface(const LDKChainWatchInterfaceUtil *this_arg); public static native long ChainWatchInterfaceUtil_as_ChainWatchInterface(long this_arg); /// MUST_USE_RES LDKChainWatchInterfaceUtil ChainWatchInterfaceUtil_new(LDKNetwork network); - public static native long ChainWatchInterfaceUtil_new(long network); + public static native long ChainWatchInterfaceUtil_new(LDKNetwork network); /// MUST_USE_RES bool ChainWatchInterfaceUtil_does_match_tx(const LDKChainWatchInterfaceUtil *this_arg, LDKTransaction tx); public static native boolean ChainWatchInterfaceUtil_does_match_tx(long this_arg, long tx); /// void OutPoint_free(LDKOutPoint this_ptr); @@ -495,7 +535,7 @@ public class bindings { /// void KeysManager_free(LDKKeysManager this_ptr); public static native void KeysManager_free(long this_ptr); /// MUST_USE_RES LDKKeysManager KeysManager_new(const uint8_t (*seed)[32], LDKNetwork network, uint64_t starting_time_secs, uint32_t starting_time_nanos); - public static native long KeysManager_new(byte[] seed, long network, long starting_time_secs, int starting_time_nanos); + public static native long KeysManager_new(byte[] seed, LDKNetwork network, long starting_time_secs, int starting_time_nanos); /// MUST_USE_RES LDKInMemoryChannelKeys KeysManager_derive_channel_keys(const LDKKeysManager *this_arg, uint64_t channel_value_satoshis, uint64_t params_1, uint64_t params_2); public static native long KeysManager_derive_channel_keys(long this_arg, long channel_value_satoshis, long params_1, long params_2); /// LDKKeysInterface KeysManager_as_KeysInterface(const LDKKeysManager *this_arg); @@ -539,7 +579,7 @@ public class bindings { /// void PaymentSendFailure_free(LDKPaymentSendFailure this_ptr); public static native void PaymentSendFailure_free(long this_ptr); /// MUST_USE_RES LDKChannelManager ChannelManager_new(LDKNetwork network, LDKFeeEstimator fee_est, LDKManyChannelMonitor monitor, LDKBroadcasterInterface tx_broadcaster, LDKLogger logger, LDKKeysInterface keys_manager, LDKUserConfig config, uintptr_t current_blockchain_height); - public static native long ChannelManager_new(long network, long fee_est, long monitor, long tx_broadcaster, long logger, long keys_manager, long config, long current_blockchain_height); + public static native long ChannelManager_new(LDKNetwork network, long fee_est, long monitor, long tx_broadcaster, long logger, long keys_manager, long config, long current_blockchain_height); /// MUST_USE_RES LDKCResult_NoneAPIErrorZ ChannelManager_create_channel(const LDKChannelManager *this_arg, LDKPublicKey their_network_key, uint64_t channel_value_satoshis, uint64_t push_msat, uint64_t user_id, LDKUserConfig override_config); public static native long ChannelManager_create_channel(long this_arg, long their_network_key, long channel_value_satoshis, long push_msat, long user_id, long override_config); /// MUST_USE_RES LDKCVec_ChannelDetailsZ ChannelManager_list_channels(const LDKChannelManager *this_arg); diff --git a/src/main/jni/bindings.c b/src/main/jni/bindings.c index db1d9c5a..f9e0a4ea 100644 --- a/src/main/jni/bindings.c +++ b/src/main/jni/bindings.c @@ -5,6 +5,12 @@ #include #include +jmethodID ordinal_meth = NULL; +JNIEXPORT void Java_org_ldk_impl_bindings_init(JNIEnv * env, jclass _b, jclass enum_class) { + ordinal_meth = (*env)->GetMethodID(env, enum_class, "ordinal", "()I"); + assert(ordinal_meth != NULL); +} + #include static mtx_t allocation_mtx; @@ -52,6 +58,246 @@ JNIEXPORT jlong JNICALL Java_org_ldk_impl_bindings_LDKSecretKey_1new(JNIEnv * _e LDKSecretKey* key = (LDKSecretKey*)MALLOC(sizeof(LDKSecretKey), "LDKSecretKey"); return (long)key; } +static inline LDKChainError LDKChainError_from_java(JNIEnv *env, jclass val) { + switch ((*env)->CallIntMethod(env, val, ordinal_meth)) { + case 0: return LDKChainError_NotSupported; + case 1: return LDKChainError_NotWatched; + case 2: return LDKChainError_UnknownTx; + } + assert(false); +} +static inline jclass LDKChainError_to_java(JNIEnv *env, LDKChainError val) { + // TODO: This is pretty inefficient, we really need to cache the field IDs and class + jclass enum_class = (*env)->FindClass(env, "Lorg/ldk/impl/bindings$LDKChainError;"); + assert(enum_class != NULL); + switch (val) { + case LDKChainError_NotSupported: { + jfieldID field = (*env)->GetStaticFieldID(env, enum_class, "LDKChainError_NotSupported", "Lorg/ldk/impl/bindings$LDKChainError;"); + assert(field != NULL); + return (*env)->GetStaticObjectField(env, enum_class, field); + } + case LDKChainError_NotWatched: { + jfieldID field = (*env)->GetStaticFieldID(env, enum_class, "LDKChainError_NotWatched", "Lorg/ldk/impl/bindings$LDKChainError;"); + assert(field != NULL); + return (*env)->GetStaticObjectField(env, enum_class, field); + } + case LDKChainError_UnknownTx: { + jfieldID field = (*env)->GetStaticFieldID(env, enum_class, "LDKChainError_UnknownTx", "Lorg/ldk/impl/bindings$LDKChainError;"); + assert(field != NULL); + return (*env)->GetStaticObjectField(env, enum_class, field); + } + default: assert(false); + } +} + +static inline LDKChannelMonitorUpdateErr LDKChannelMonitorUpdateErr_from_java(JNIEnv *env, jclass val) { + switch ((*env)->CallIntMethod(env, val, ordinal_meth)) { + case 0: return LDKChannelMonitorUpdateErr_TemporaryFailure; + case 1: return LDKChannelMonitorUpdateErr_PermanentFailure; + } + assert(false); +} +static inline jclass LDKChannelMonitorUpdateErr_to_java(JNIEnv *env, LDKChannelMonitorUpdateErr val) { + // TODO: This is pretty inefficient, we really need to cache the field IDs and class + jclass enum_class = (*env)->FindClass(env, "Lorg/ldk/impl/bindings$LDKChannelMonitorUpdateErr;"); + assert(enum_class != NULL); + switch (val) { + case LDKChannelMonitorUpdateErr_TemporaryFailure: { + jfieldID field = (*env)->GetStaticFieldID(env, enum_class, "LDKChannelMonitorUpdateErr_TemporaryFailure", "Lorg/ldk/impl/bindings$LDKChannelMonitorUpdateErr;"); + assert(field != NULL); + return (*env)->GetStaticObjectField(env, enum_class, field); + } + case LDKChannelMonitorUpdateErr_PermanentFailure: { + jfieldID field = (*env)->GetStaticFieldID(env, enum_class, "LDKChannelMonitorUpdateErr_PermanentFailure", "Lorg/ldk/impl/bindings$LDKChannelMonitorUpdateErr;"); + assert(field != NULL); + return (*env)->GetStaticObjectField(env, enum_class, field); + } + default: assert(false); + } +} + +static inline LDKConfirmationTarget LDKConfirmationTarget_from_java(JNIEnv *env, jclass val) { + switch ((*env)->CallIntMethod(env, val, ordinal_meth)) { + case 0: return LDKConfirmationTarget_Background; + case 1: return LDKConfirmationTarget_Normal; + case 2: return LDKConfirmationTarget_HighPriority; + } + assert(false); +} +static inline jclass LDKConfirmationTarget_to_java(JNIEnv *env, LDKConfirmationTarget val) { + // TODO: This is pretty inefficient, we really need to cache the field IDs and class + jclass enum_class = (*env)->FindClass(env, "Lorg/ldk/impl/bindings$LDKConfirmationTarget;"); + assert(enum_class != NULL); + switch (val) { + case LDKConfirmationTarget_Background: { + jfieldID field = (*env)->GetStaticFieldID(env, enum_class, "LDKConfirmationTarget_Background", "Lorg/ldk/impl/bindings$LDKConfirmationTarget;"); + assert(field != NULL); + return (*env)->GetStaticObjectField(env, enum_class, field); + } + case LDKConfirmationTarget_Normal: { + jfieldID field = (*env)->GetStaticFieldID(env, enum_class, "LDKConfirmationTarget_Normal", "Lorg/ldk/impl/bindings$LDKConfirmationTarget;"); + assert(field != NULL); + return (*env)->GetStaticObjectField(env, enum_class, field); + } + case LDKConfirmationTarget_HighPriority: { + jfieldID field = (*env)->GetStaticFieldID(env, enum_class, "LDKConfirmationTarget_HighPriority", "Lorg/ldk/impl/bindings$LDKConfirmationTarget;"); + assert(field != NULL); + return (*env)->GetStaticObjectField(env, enum_class, field); + } + default: assert(false); + } +} + +static inline LDKLevel LDKLevel_from_java(JNIEnv *env, jclass val) { + switch ((*env)->CallIntMethod(env, val, ordinal_meth)) { + case 0: return LDKLevel_Off; + case 1: return LDKLevel_Error; + case 2: return LDKLevel_Warn; + case 3: return LDKLevel_Info; + case 4: return LDKLevel_Debug; + case 5: return LDKLevel_Trace; + } + assert(false); +} +static inline jclass LDKLevel_to_java(JNIEnv *env, LDKLevel val) { + // TODO: This is pretty inefficient, we really need to cache the field IDs and class + jclass enum_class = (*env)->FindClass(env, "Lorg/ldk/impl/bindings$LDKLevel;"); + assert(enum_class != NULL); + switch (val) { + case LDKLevel_Off: { + jfieldID field = (*env)->GetStaticFieldID(env, enum_class, "LDKLevel_Off", "Lorg/ldk/impl/bindings$LDKLevel;"); + assert(field != NULL); + return (*env)->GetStaticObjectField(env, enum_class, field); + } + case LDKLevel_Error: { + jfieldID field = (*env)->GetStaticFieldID(env, enum_class, "LDKLevel_Error", "Lorg/ldk/impl/bindings$LDKLevel;"); + assert(field != NULL); + return (*env)->GetStaticObjectField(env, enum_class, field); + } + case LDKLevel_Warn: { + jfieldID field = (*env)->GetStaticFieldID(env, enum_class, "LDKLevel_Warn", "Lorg/ldk/impl/bindings$LDKLevel;"); + assert(field != NULL); + return (*env)->GetStaticObjectField(env, enum_class, field); + } + case LDKLevel_Info: { + jfieldID field = (*env)->GetStaticFieldID(env, enum_class, "LDKLevel_Info", "Lorg/ldk/impl/bindings$LDKLevel;"); + assert(field != NULL); + return (*env)->GetStaticObjectField(env, enum_class, field); + } + case LDKLevel_Debug: { + jfieldID field = (*env)->GetStaticFieldID(env, enum_class, "LDKLevel_Debug", "Lorg/ldk/impl/bindings$LDKLevel;"); + assert(field != NULL); + return (*env)->GetStaticObjectField(env, enum_class, field); + } + case LDKLevel_Trace: { + jfieldID field = (*env)->GetStaticFieldID(env, enum_class, "LDKLevel_Trace", "Lorg/ldk/impl/bindings$LDKLevel;"); + assert(field != NULL); + return (*env)->GetStaticObjectField(env, enum_class, field); + } + default: assert(false); + } +} + +static inline LDKNetwork LDKNetwork_from_java(JNIEnv *env, jclass val) { + switch ((*env)->CallIntMethod(env, val, ordinal_meth)) { + case 0: return LDKNetwork_Bitcoin; + case 1: return LDKNetwork_Testnet; + case 2: return LDKNetwork_Regtest; + } + assert(false); +} +static inline jclass LDKNetwork_to_java(JNIEnv *env, LDKNetwork val) { + // TODO: This is pretty inefficient, we really need to cache the field IDs and class + jclass enum_class = (*env)->FindClass(env, "Lorg/ldk/impl/bindings$LDKNetwork;"); + assert(enum_class != NULL); + switch (val) { + case LDKNetwork_Bitcoin: { + jfieldID field = (*env)->GetStaticFieldID(env, enum_class, "LDKNetwork_Bitcoin", "Lorg/ldk/impl/bindings$LDKNetwork;"); + assert(field != NULL); + return (*env)->GetStaticObjectField(env, enum_class, field); + } + case LDKNetwork_Testnet: { + jfieldID field = (*env)->GetStaticFieldID(env, enum_class, "LDKNetwork_Testnet", "Lorg/ldk/impl/bindings$LDKNetwork;"); + assert(field != NULL); + return (*env)->GetStaticObjectField(env, enum_class, field); + } + case LDKNetwork_Regtest: { + jfieldID field = (*env)->GetStaticFieldID(env, enum_class, "LDKNetwork_Regtest", "Lorg/ldk/impl/bindings$LDKNetwork;"); + assert(field != NULL); + return (*env)->GetStaticObjectField(env, enum_class, field); + } + default: assert(false); + } +} + +static inline LDKSecp256k1Error LDKSecp256k1Error_from_java(JNIEnv *env, jclass val) { + switch ((*env)->CallIntMethod(env, val, ordinal_meth)) { + case 0: return LDKSecp256k1Error_IncorrectSignature; + case 1: return LDKSecp256k1Error_InvalidMessage; + case 2: return LDKSecp256k1Error_InvalidPublicKey; + case 3: return LDKSecp256k1Error_InvalidSignature; + case 4: return LDKSecp256k1Error_InvalidSecretKey; + case 5: return LDKSecp256k1Error_InvalidRecoveryId; + case 6: return LDKSecp256k1Error_InvalidTweak; + case 7: return LDKSecp256k1Error_NotEnoughMemory; + case 8: return LDKSecp256k1Error_CallbackPanicked; + } + assert(false); +} +static inline jclass LDKSecp256k1Error_to_java(JNIEnv *env, LDKSecp256k1Error val) { + // TODO: This is pretty inefficient, we really need to cache the field IDs and class + jclass enum_class = (*env)->FindClass(env, "Lorg/ldk/impl/bindings$LDKSecp256k1Error;"); + assert(enum_class != NULL); + switch (val) { + case LDKSecp256k1Error_IncorrectSignature: { + jfieldID field = (*env)->GetStaticFieldID(env, enum_class, "LDKSecp256k1Error_IncorrectSignature", "Lorg/ldk/impl/bindings$LDKSecp256k1Error;"); + assert(field != NULL); + return (*env)->GetStaticObjectField(env, enum_class, field); + } + case LDKSecp256k1Error_InvalidMessage: { + jfieldID field = (*env)->GetStaticFieldID(env, enum_class, "LDKSecp256k1Error_InvalidMessage", "Lorg/ldk/impl/bindings$LDKSecp256k1Error;"); + assert(field != NULL); + return (*env)->GetStaticObjectField(env, enum_class, field); + } + case LDKSecp256k1Error_InvalidPublicKey: { + jfieldID field = (*env)->GetStaticFieldID(env, enum_class, "LDKSecp256k1Error_InvalidPublicKey", "Lorg/ldk/impl/bindings$LDKSecp256k1Error;"); + assert(field != NULL); + return (*env)->GetStaticObjectField(env, enum_class, field); + } + case LDKSecp256k1Error_InvalidSignature: { + jfieldID field = (*env)->GetStaticFieldID(env, enum_class, "LDKSecp256k1Error_InvalidSignature", "Lorg/ldk/impl/bindings$LDKSecp256k1Error;"); + assert(field != NULL); + return (*env)->GetStaticObjectField(env, enum_class, field); + } + case LDKSecp256k1Error_InvalidSecretKey: { + jfieldID field = (*env)->GetStaticFieldID(env, enum_class, "LDKSecp256k1Error_InvalidSecretKey", "Lorg/ldk/impl/bindings$LDKSecp256k1Error;"); + assert(field != NULL); + return (*env)->GetStaticObjectField(env, enum_class, field); + } + case LDKSecp256k1Error_InvalidRecoveryId: { + jfieldID field = (*env)->GetStaticFieldID(env, enum_class, "LDKSecp256k1Error_InvalidRecoveryId", "Lorg/ldk/impl/bindings$LDKSecp256k1Error;"); + assert(field != NULL); + return (*env)->GetStaticObjectField(env, enum_class, field); + } + case LDKSecp256k1Error_InvalidTweak: { + jfieldID field = (*env)->GetStaticFieldID(env, enum_class, "LDKSecp256k1Error_InvalidTweak", "Lorg/ldk/impl/bindings$LDKSecp256k1Error;"); + assert(field != NULL); + return (*env)->GetStaticObjectField(env, enum_class, field); + } + case LDKSecp256k1Error_NotEnoughMemory: { + jfieldID field = (*env)->GetStaticFieldID(env, enum_class, "LDKSecp256k1Error_NotEnoughMemory", "Lorg/ldk/impl/bindings$LDKSecp256k1Error;"); + assert(field != NULL); + return (*env)->GetStaticObjectField(env, enum_class, field); + } + case LDKSecp256k1Error_CallbackPanicked: { + jfieldID field = (*env)->GetStaticFieldID(env, enum_class, "LDKSecp256k1Error_CallbackPanicked", "Lorg/ldk/impl/bindings$LDKSecp256k1Error;"); + assert(field != NULL); + return (*env)->GetStaticObjectField(env, enum_class, field); + } + default: assert(false); + } +} + typedef struct LDKMessageSendEventsProvider_JCalls { atomic_size_t refcnt; JNIEnv *env; @@ -394,7 +640,8 @@ typedef struct LDKFeeEstimator_JCalls { } LDKFeeEstimator_JCalls; uint32_t get_est_sat_per_1000_weight_jcall(const void* this_arg, LDKConfirmationTarget confirmation_target) { LDKFeeEstimator_JCalls *j_calls = (LDKFeeEstimator_JCalls*) this_arg; - return (*j_calls->env)->CallIntMethod(j_calls->env, j_calls->o, j_calls->get_est_sat_per_1000_weight_meth, confirmation_target); + jclass confirmation_target_conv = LDKConfirmationTarget_to_java(j_calls->env, confirmation_target); + return (*j_calls->env)->CallIntMethod(j_calls->env, j_calls->o, j_calls->get_est_sat_per_1000_weight_meth, confirmation_target_conv); } static void LDKFeeEstimator_JCalls_free(void* this_arg) { LDKFeeEstimator_JCalls *j_calls = (LDKFeeEstimator_JCalls*) this_arg; @@ -415,7 +662,7 @@ static inline LDKFeeEstimator LDKFeeEstimator_init (JNIEnv * env, jclass _a, job atomic_init(&calls->refcnt, 1); calls->env = env; calls->o = (*env)->NewGlobalRef(env, o); - calls->get_est_sat_per_1000_weight_meth = (*env)->GetMethodID(env, c, "get_est_sat_per_1000_weight", "(J)I"); + calls->get_est_sat_per_1000_weight_meth = (*env)->GetMethodID(env, c, "get_est_sat_per_1000_weight", "(Lorg/ldk/impl/bindings$LDKConfirmationTarget;)I"); assert(calls->get_est_sat_per_1000_weight_meth != NULL); LDKFeeEstimator ret = { @@ -1160,7 +1407,7 @@ JNIEXPORT void JNICALL Java_org_ldk_impl_bindings_C3Tuple_1ChannelAnnouncementCh return C3Tuple_ChannelAnnouncementChannelUpdateChannelUpdateZ_free(arg_conv); } -JNIEXPORT jlong JNICALL Java_org_ldk_impl_bindings_CResult_1C2Tuple_1Scriptu64ZChainErrorZ_1err(JNIEnv * _env, jclass _b, jlong arg) { +JNIEXPORT jlong JNICALL Java_org_ldk_impl_bindings_CResult_1C2Tuple_1Scriptu64ZChainErrorZ_1err(JNIEnv * _env, jclass _b, jclass arg) { LDKChainError arg_conv = *(LDKChainError*)arg; FREE((void*)arg); LDKCResult_C2Tuple_Scriptu64ZChainErrorZ* ret = MALLOC(sizeof(LDKCResult_C2Tuple_Scriptu64ZChainErrorZ), "LDKCResult_C2Tuple_Scriptu64ZChainErrorZ"); @@ -1246,7 +1493,7 @@ JNIEXPORT void JNICALL Java_org_ldk_impl_bindings_CResult_1NoneAPIErrorZ_1free(J return CResult_NoneAPIErrorZ_free(arg_conv); } -JNIEXPORT jlong JNICALL Java_org_ldk_impl_bindings_CResult_1NoneChannelMonitorUpdateErrZ_1err(JNIEnv * _env, jclass _b, jlong arg) { +JNIEXPORT jlong JNICALL Java_org_ldk_impl_bindings_CResult_1NoneChannelMonitorUpdateErrZ_1err(JNIEnv * _env, jclass _b, jclass arg) { LDKChannelMonitorUpdateErr arg_conv = *(LDKChannelMonitorUpdateErr*)arg; FREE((void*)arg); LDKCResult_NoneChannelMonitorUpdateErrZ* ret = MALLOC(sizeof(LDKCResult_NoneChannelMonitorUpdateErrZ), "LDKCResult_NoneChannelMonitorUpdateErrZ"); @@ -1338,7 +1585,7 @@ JNIEXPORT jlong JNICALL Java_org_ldk_impl_bindings_CResult_1SignatureNoneZ_1ok(J return (long)ret; } -JNIEXPORT jlong JNICALL Java_org_ldk_impl_bindings_CResult_1TxCreationKeysSecpErrorZ_1err(JNIEnv * _env, jclass _b, jlong arg) { +JNIEXPORT jlong JNICALL Java_org_ldk_impl_bindings_CResult_1TxCreationKeysSecpErrorZ_1err(JNIEnv * _env, jclass _b, jclass arg) { LDKSecp256k1Error arg_conv = *(LDKSecp256k1Error*)arg; FREE((void*)arg); LDKCResult_TxCreationKeysSecpErrorZ* ret = MALLOC(sizeof(LDKCResult_TxCreationKeysSecpErrorZ), "LDKCResult_TxCreationKeysSecpErrorZ"); @@ -1697,10 +1944,9 @@ JNIEXPORT void JNICALL Java_org_ldk_impl_bindings_APIError_1free(JNIEnv * _env, return APIError_free(this_ptr_conv); } -JNIEXPORT jlong JNICALL Java_org_ldk_impl_bindings_Level_1max(JNIEnv * _env, jclass _b) { - LDKLevel* ret = MALLOC(sizeof(LDKLevel), "LDKLevel"); - *ret = Level_max(); - return (long)ret; +JNIEXPORT jclass JNICALL Java_org_ldk_impl_bindings_Level_1max(JNIEnv * _env, jclass _b) { + jclass ret = LDKLevel_to_java(_env, Level_max()); + return ret; } JNIEXPORT void JNICALL Java_org_ldk_impl_bindings_Logger_1free(JNIEnv * _env, jclass _b, jlong this_ptr) { @@ -2173,9 +2419,8 @@ JNIEXPORT jlong JNICALL Java_org_ldk_impl_bindings_ChainWatchInterfaceUtil_1as_1 return (long)ret; } -JNIEXPORT jlong JNICALL Java_org_ldk_impl_bindings_ChainWatchInterfaceUtil_1new(JNIEnv * _env, jclass _b, jlong network) { - LDKNetwork network_conv = *(LDKNetwork*)network; - FREE((void*)network); +JNIEXPORT jlong JNICALL Java_org_ldk_impl_bindings_ChainWatchInterfaceUtil_1new(JNIEnv * _env, jclass _b, jclass network) { + LDKNetwork network_conv = LDKNetwork_from_java(_env, network); LDKChainWatchInterfaceUtil* ret = MALLOC(sizeof(LDKChainWatchInterfaceUtil), "LDKChainWatchInterfaceUtil"); *ret = ChainWatchInterfaceUtil_new(network_conv); assert(!ret->_underlying_ref); @@ -2436,12 +2681,11 @@ JNIEXPORT void JNICALL Java_org_ldk_impl_bindings_KeysManager_1free(JNIEnv * _en return KeysManager_free(this_ptr_conv); } -JNIEXPORT jlong JNICALL Java_org_ldk_impl_bindings_KeysManager_1new(JNIEnv * _env, jclass _b, jbyteArray seed, jlong network, jlong starting_time_secs, jint starting_time_nanos) { +JNIEXPORT jlong JNICALL Java_org_ldk_impl_bindings_KeysManager_1new(JNIEnv * _env, jclass _b, jbyteArray seed, jclass network, jlong starting_time_secs, jint starting_time_nanos) { unsigned char seed_arr[32]; (*_env)->GetByteArrayRegion (_env, seed, 0, 32, seed_arr); unsigned char (*seed_ref)[32] = &seed_arr; - LDKNetwork network_conv = *(LDKNetwork*)network; - FREE((void*)network); + LDKNetwork network_conv = LDKNetwork_from_java(_env, network); LDKKeysManager* ret = MALLOC(sizeof(LDKKeysManager), "LDKKeysManager"); *ret = KeysManager_new(seed_ref, network_conv, starting_time_secs, starting_time_nanos); assert(!ret->_underlying_ref); @@ -2581,9 +2825,8 @@ JNIEXPORT void JNICALL Java_org_ldk_impl_bindings_PaymentSendFailure_1free(JNIEn return PaymentSendFailure_free(this_ptr_conv); } -JNIEXPORT jlong JNICALL Java_org_ldk_impl_bindings_ChannelManager_1new(JNIEnv * _env, jclass _b, jlong network, jlong fee_est, jlong monitor, jlong tx_broadcaster, jlong logger, jlong keys_manager, jlong config, jlong current_blockchain_height) { - LDKNetwork network_conv = *(LDKNetwork*)network; - FREE((void*)network); +JNIEXPORT jlong JNICALL Java_org_ldk_impl_bindings_ChannelManager_1new(JNIEnv * _env, jclass _b, jclass network, jlong fee_est, jlong monitor, jlong tx_broadcaster, jlong logger, jlong keys_manager, jlong config, jlong current_blockchain_height) { + LDKNetwork network_conv = LDKNetwork_from_java(_env, network); LDKFeeEstimator fee_est_conv = *(LDKFeeEstimator*)fee_est; LDKFeeEstimator_JCalls_clone(fee_est_conv.this_arg); LDKManyChannelMonitor monitor_conv = *(LDKManyChannelMonitor*)monitor; diff --git a/src/main/jni/org_ldk_impl_bindings.h b/src/main/jni/org_ldk_impl_bindings.h index cafe0b4e..69f66a2b 100644 --- a/src/main/jni/org_ldk_impl_bindings.h +++ b/src/main/jni/org_ldk_impl_bindings.h @@ -7,6 +7,14 @@ #ifdef __cplusplus extern "C" { #endif +/* + * Class: org_ldk_impl_bindings + * Method: init + * Signature: (Ljava/lang/Class;)V + */ +JNIEXPORT void JNICALL Java_org_ldk_impl_bindings_init + (JNIEnv *, jclass, jclass); + /* * Class: org_ldk_impl_bindings * Method: LDKSecretKey_new @@ -178,10 +186,10 @@ JNIEXPORT void JNICALL Java_org_ldk_impl_bindings_C3Tuple_1ChannelAnnouncementCh /* * Class: org_ldk_impl_bindings * Method: CResult_C2Tuple_Scriptu64ZChainErrorZ_err - * Signature: (J)J + * Signature: (Lorg/ldk/impl/bindings/LDKChainError;)J */ JNIEXPORT jlong JNICALL Java_org_ldk_impl_bindings_CResult_1C2Tuple_1Scriptu64ZChainErrorZ_1err - (JNIEnv *, jclass, jlong); + (JNIEnv *, jclass, jobject); /* * Class: org_ldk_impl_bindings @@ -274,10 +282,10 @@ JNIEXPORT void JNICALL Java_org_ldk_impl_bindings_CResult_1NoneAPIErrorZ_1free /* * Class: org_ldk_impl_bindings * Method: CResult_NoneChannelMonitorUpdateErrZ_err - * Signature: (J)J + * Signature: (Lorg/ldk/impl/bindings/LDKChannelMonitorUpdateErr;)J */ JNIEXPORT jlong JNICALL Java_org_ldk_impl_bindings_CResult_1NoneChannelMonitorUpdateErrZ_1err - (JNIEnv *, jclass, jlong); + (JNIEnv *, jclass, jobject); /* * Class: org_ldk_impl_bindings @@ -378,10 +386,10 @@ JNIEXPORT jlong JNICALL Java_org_ldk_impl_bindings_CResult_1SignatureNoneZ_1ok /* * Class: org_ldk_impl_bindings * Method: CResult_TxCreationKeysSecpErrorZ_err - * Signature: (J)J + * Signature: (Lorg/ldk/impl/bindings/LDKSecp256k1Error;)J */ JNIEXPORT jlong JNICALL Java_org_ldk_impl_bindings_CResult_1TxCreationKeysSecpErrorZ_1err - (JNIEnv *, jclass, jlong); + (JNIEnv *, jclass, jobject); /* * Class: org_ldk_impl_bindings @@ -810,9 +818,9 @@ JNIEXPORT void JNICALL Java_org_ldk_impl_bindings_APIError_1free /* * Class: org_ldk_impl_bindings * Method: Level_max - * Signature: ()J + * Signature: ()Lorg/ldk/impl/bindings/LDKLevel; */ -JNIEXPORT jlong JNICALL Java_org_ldk_impl_bindings_Level_1max +JNIEXPORT jobject JNICALL Java_org_ldk_impl_bindings_Level_1max (JNIEnv *, jclass); /* @@ -1386,10 +1394,10 @@ JNIEXPORT jlong JNICALL Java_org_ldk_impl_bindings_ChainWatchInterfaceUtil_1as_1 /* * Class: org_ldk_impl_bindings * Method: ChainWatchInterfaceUtil_new - * Signature: (J)J + * Signature: (Lorg/ldk/impl/bindings/LDKNetwork;)J */ JNIEXPORT jlong JNICALL Java_org_ldk_impl_bindings_ChainWatchInterfaceUtil_1new - (JNIEnv *, jclass, jlong); + (JNIEnv *, jclass, jobject); /* * Class: org_ldk_impl_bindings @@ -1666,10 +1674,10 @@ JNIEXPORT void JNICALL Java_org_ldk_impl_bindings_KeysManager_1free /* * Class: org_ldk_impl_bindings * Method: KeysManager_new - * Signature: ([BJJI)J + * Signature: ([BLorg/ldk/impl/bindings/LDKNetwork;JI)J */ JNIEXPORT jlong JNICALL Java_org_ldk_impl_bindings_KeysManager_1new - (JNIEnv *, jclass, jbyteArray, jlong, jlong, jint); + (JNIEnv *, jclass, jbyteArray, jobject, jlong, jint); /* * Class: org_ldk_impl_bindings @@ -1842,10 +1850,10 @@ JNIEXPORT void JNICALL Java_org_ldk_impl_bindings_PaymentSendFailure_1free /* * Class: org_ldk_impl_bindings * Method: ChannelManager_new - * Signature: (JJJJJJJJ)J + * Signature: (Lorg/ldk/impl/bindings/LDKNetwork;JJJJJJJ)J */ JNIEXPORT jlong JNICALL Java_org_ldk_impl_bindings_ChannelManager_1new - (JNIEnv *, jclass, jlong, jlong, jlong, jlong, jlong, jlong, jlong, jlong); + (JNIEnv *, jclass, jobject, jlong, jlong, jlong, jlong, jlong, jlong, jlong); /* * Class: org_ldk_impl_bindings diff --git a/src/test/java/org/ldk/ManualMsgHandlingPeerTest.java b/src/test/java/org/ldk/ManualMsgHandlingPeerTest.java index 010b4075..38c73682 100644 --- a/src/test/java/org/ldk/ManualMsgHandlingPeerTest.java +++ b/src/test/java/org/ldk/ManualMsgHandlingPeerTest.java @@ -135,6 +135,9 @@ public class ManualMsgHandlingPeerTest { long peer_manager = bindings.PeerManager_new(message_handler, our_node_secret, random_data, logger); + // Test Level_max() since its the only place we create a java object from a Rust-returned enum. + assert bindings.Level_max() == bindings.LDKLevel.LDKLevel_Trace; + // Note that we can't rely on finalizer order, so don't bother trying to rely on it here bindings.Logger_free(logger); bindings.ChannelMessageHandler_free(chan_handler); -- 2.39.5