Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ jobs:
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Pin syn and quote to meet MSRV
run: |
cd lightning-c-bindings
cargo update -p syn --precise "2.0.106" --verbose
cargo update -p quote --precise "1.0.41" --verbose
- name: Sanity test bindings against Cargo.toml RL
working-directory: lightning-c-bindings
run: |
Expand All @@ -46,7 +51,7 @@ jobs:
run: |
git clone https://github.com/rust-bitcoin/rust-lightning
cd rust-lightning
git checkout 0.1-bindings
git checkout 0.2-bindings
- name: Fix Github Actions to not be broken
run: git config --global --add safe.directory /__w/ldk-c-bindings/ldk-c-bindings
- name: Pin proc-macro and quote to meet MSRV
Expand Down Expand Up @@ -106,7 +111,7 @@ jobs:
run: |
git clone https://github.com/rust-bitcoin/rust-lightning
cd rust-lightning
git checkout 0.1-bindings
git checkout 0.2-bindings
- name: Fix Github Actions to not be broken
run: git config --global --add safe.directory /__w/ldk-c-bindings/ldk-c-bindings
- name: Fetch MacOS SDK
Expand Down Expand Up @@ -152,7 +157,7 @@ jobs:
run: |
git clone https://github.com/rust-bitcoin/rust-lightning
cd rust-lightning
git checkout 0.1-bindings
git checkout 0.2-bindings
- name: Rebuild bindings using Apple clang, and check the sample app builds + links
run: ./genbindings.sh ./rust-lightning true
- name: Rebuild bindings using upstream clang, and check the sample app builds + links
Expand Down
8 changes: 4 additions & 4 deletions c-bindings-gen/src/blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,13 +226,13 @@ pub fn write_vec_block<W: std::io::Write>(w: &mut W, mangled_container: &str, in
writeln!(w, "impl {} {{", mangled_container).unwrap();
writeln!(w, "\t#[allow(unused)] pub(crate) fn into_rust(&mut self) -> Vec<{}> {{", inner_type).unwrap();
writeln!(w, "\t\tif self.datalen == 0 {{ return Vec::new(); }}").unwrap();
writeln!(w, "\t\tlet ret = unsafe {{ Box::from_raw(core::slice::from_raw_parts_mut(self.data, self.datalen)) }}.into();").unwrap();
writeln!(w, "\t\tlet ret = unsafe {{ Box::from_raw(crate::c_types::from_raw_parts_safer_mut(self.data, self.datalen)) }}.into();").unwrap();
writeln!(w, "\t\tself.data = core::ptr::null_mut();").unwrap();
writeln!(w, "\t\tself.datalen = 0;").unwrap();
writeln!(w, "\t\tret").unwrap();
writeln!(w, "\t}}").unwrap();
writeln!(w, "\t#[allow(unused)] pub(crate) fn as_slice(&self) -> &[{}] {{", inner_type).unwrap();
writeln!(w, "\t\tunsafe {{ core::slice::from_raw_parts_mut(self.data, self.datalen) }}").unwrap();
writeln!(w, "\t\tunsafe {{ crate::c_types::from_raw_parts_safer_mut(self.data, self.datalen) }}").unwrap();
writeln!(w, "\t}}").unwrap();
writeln!(w, "}}").unwrap();

Expand All @@ -250,15 +250,15 @@ pub fn write_vec_block<W: std::io::Write>(w: &mut W, mangled_container: &str, in
writeln!(w, "impl Drop for {} {{", mangled_container).unwrap();
writeln!(w, "\tfn drop(&mut self) {{").unwrap();
writeln!(w, "\t\tif self.datalen == 0 {{ return; }}").unwrap();
writeln!(w, "\t\tlet _ = unsafe {{ Box::from_raw(core::slice::from_raw_parts_mut(self.data, self.datalen)) }};").unwrap();
writeln!(w, "\t\tlet _ = unsafe {{ Box::from_raw(crate::c_types::from_raw_parts_safer_mut(self.data, self.datalen)) }};").unwrap();
writeln!(w, "\t}}").unwrap();
writeln!(w, "}}").unwrap();
if clonable {
writeln!(w, "impl Clone for {} {{", mangled_container).unwrap();
writeln!(w, "\tfn clone(&self) -> Self {{").unwrap();
writeln!(w, "\t\tlet mut res = Vec::new();").unwrap();
writeln!(w, "\t\tif self.datalen == 0 {{ return Self::from(res); }}").unwrap();
writeln!(w, "\t\tres.extend_from_slice(unsafe {{ core::slice::from_raw_parts_mut(self.data, self.datalen) }});").unwrap();
writeln!(w, "\t\tres.extend_from_slice(unsafe {{ crate::c_types::from_raw_parts_safer_mut(self.data, self.datalen) }});").unwrap();
writeln!(w, "\t\tSelf::from(res)").unwrap();
writeln!(w, "\t}}").unwrap();
writeln!(w, "}}").unwrap();
Expand Down
49 changes: 40 additions & 9 deletions c-bindings-gen/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ fn maybe_convert_trait_impl<W: std::io::Write>(w: &mut W, trait_path: &syn::Path
}
writeln!(w, "}}").unwrap();
},
"lightning::util::ser::Readable"|"lightning::util::ser::ReadableArgs"|"lightning::util::ser::MaybeReadable" => {
"lightning::util::ser::Readable"|"lightning::util::ser::LengthReadable"|"lightning::util::ser::ReadableArgs"|"lightning::util::ser::MaybeReadable" => {
// Create the Result<Object, DecodeError> syn::Type
let mut res_ty: syn::Type = parse_quote!(Result<#for_ty, lightning::ln::msgs::DecodeError>);

Expand Down Expand Up @@ -850,7 +850,7 @@ fn writeln_struct<'a, 'b, W: std::io::Write>(w: &mut W, s: &'a syn::ItemStruct,
writeln_arg_docs(w, &$field.attrs, "", types, Some(&gen_types), vec![].drain(..), Some(&ref_type));
write!(w, "#[no_mangle]\npub extern \"C\" fn {}_get_{}(this_ptr: &{}) -> ", struct_name, $new_name, struct_name).unwrap();
types.write_c_type(w, &ref_type, Some(&gen_types), true);
write!(w, " {{\n\tlet mut inner_val = &mut this_ptr.get_native_mut_ref().{};\n\t", $real_name).unwrap();
write!(w, " {{\n\tlet mut inner_val = &mut {}::get_native_mut_ref(this_ptr).{};\n\t", struct_name, $real_name).unwrap();
let local_var = types.write_to_c_conversion_from_ownable_ref_new_var(w, &format_ident!("inner_val"), &ref_type, Some(&gen_types));
if local_var { write!(w, "\n\t").unwrap(); }
types.write_to_c_conversion_inline_prefix(w, &ref_type, Some(&gen_types), true);
Expand All @@ -867,7 +867,7 @@ fn writeln_struct<'a, 'b, W: std::io::Write>(w: &mut W, s: &'a syn::ItemStruct,
writeln_arg_docs(w, &$field.attrs, "", types, Some(&gen_types), vec![].drain(..), Some(&$field.ty));
writeln!(w, "///\n/// Returns a copy of the field.").unwrap();
write!(w, "#[no_mangle]\npub extern \"C\" fn {}_get_{}(this_ptr: &{}) -> {}", struct_name, $new_name, struct_name, s).unwrap();
write!(w, " {{\n\tlet mut inner_val = this_ptr.get_native_mut_ref().{}.clone();\n\t", $real_name).unwrap();
write!(w, " {{\n\tlet mut inner_val = {}::get_native_mut_ref(this_ptr).{}.clone();\n\t", struct_name, $real_name).unwrap();
let local_var = types.write_to_c_conversion_new_var(w, &format_ident!("inner_val"), &$field.ty, Some(&gen_types), true);
if local_var { write!(w, "\n\t").unwrap(); }
types.write_to_c_conversion_inline_prefix(w, &$field.ty, Some(&gen_types), true);
Expand Down Expand Up @@ -981,8 +981,6 @@ fn writeln_struct<'a, 'b, W: std::io::Write>(w: &mut W, s: &'a syn::ItemStruct,
write!(w, "\t}}").unwrap();
},
syn::Fields::Unnamed(fields) => {
assert!(!s.generics.params.iter()
.any(|gen| if let syn::GenericParam::Lifetime(_) = gen { false } else { true }));
writeln!(w, "{} (", types.maybe_resolve_ident(&s.ident).unwrap()).unwrap();
for (idx, field) in fields.unnamed.iter().enumerate() {
write!(w, "\t\t").unwrap();
Expand Down Expand Up @@ -1395,7 +1393,39 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, w_uses: &mut HashSet<String, NonRa
// instantiated.
return;
}
if path_matches_nongeneric(&trait_path.1, &["From"]) {
if path_matches_ignoring_generics(&trait_path.1, &["From"]) {
let from_ty;
if let syn::PathArguments::AngleBracketed(args) = &trait_path.1.segments.last().unwrap().arguments {
assert_eq!(args.args.len(), 1);
if let syn::GenericArgument::Type(ref ty) = &args.args[0] {
from_ty = ty;
} else {
panic!("From needs arguments?");
}
} else {
panic!("From needs arguments?");
}
let to_std = resolved_path.starts_with("core::") || resolved_path.starts_with("std::");
if !to_std && types.understood_c_type(&from_ty, Some(&gen_types)) {
if let syn::Type::Path(from_path) = &from_ty {
let mut from_resolved_bytes = Vec::new();
types.write_c_type(&mut from_resolved_bytes, from_ty, Some(&gen_types), true);
let from_resolved = String::from_utf8(from_resolved_bytes).unwrap();
let from_ty_ident = from_resolved.rsplit("::").next().unwrap();
writeln!(w, "#[no_mangle]").unwrap();
writeln!(w, "/// Build a {ident} from a {from_ty_ident}").unwrap();
writeln!(w, "pub extern \"C\" fn {ident}_from_{from_ty_ident}(f: {from_resolved}) -> crate::{resolved_path} {{").unwrap();
write!(w, "\tlet from_obj = ").unwrap();
types.write_from_c_conversion_prefix(w, from_ty, Some(&gen_types));
write!(w, "f").unwrap();
types.write_from_c_conversion_suffix(w, from_ty, Some(&gen_types));
write!(w, ";\n\t").unwrap();
types.write_to_c_conversion_inline_prefix(w, &*i.self_ty, Some(&gen_types), true);
write!(w, "({resolved_path}::from(from_obj))").unwrap();
types.write_to_c_conversion_inline_suffix(w, &*i.self_ty, Some(&gen_types), true);
writeln!(w, "\n}}").unwrap();
} else { panic!("wat {:?}", from_ty); }
}
} else if path_matches_nongeneric(&trait_path.1, &["Default"]) {
writeln!(w, "/// Creates a \"default\" {}. See struct and individual field documentaiton for details on which values are used.", ident).unwrap();
write!(w, "#[must_use]\n#[no_mangle]\npub extern \"C\" fn {}_default() -> {} {{\n", ident, ident).unwrap();
Expand Down Expand Up @@ -1454,18 +1484,18 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, w_uses: &mut HashSet<String, NonRa
writeln!(w, "\tfn clone(&self) -> Self {{").unwrap();
writeln!(w, "\t\tSelf {{").unwrap();
writeln!(w, "\t\t\tinner: if <*mut native{}>::is_null(self.inner) {{ core::ptr::null_mut() }} else {{", ident).unwrap();
writeln!(w, "\t\t\t\tObjOps::heap_alloc(unsafe {{ &*ObjOps::untweak_ptr(self.inner) }}.clone()) }},").unwrap();
writeln!(w, "\t\t\t\tObjOps::heap_alloc(Clone::clone(unsafe {{ &*ObjOps::untweak_ptr(self.inner) }})) }},").unwrap();
writeln!(w, "\t\t\tis_owned: true,").unwrap();
writeln!(w, "\t\t}}\n\t}}\n}}").unwrap();
writeln!(w, "#[allow(unused)]").unwrap();
writeln!(w, "/// Used only if an object of this type is returned as a trait impl by a method").unwrap();
writeln!(w, "pub(crate) extern \"C\" fn {}_clone_void(this_ptr: *const c_void) -> *mut c_void {{", ident).unwrap();
writeln!(w, "\tBox::into_raw(Box::new(unsafe {{ (*(this_ptr as *const native{})).clone() }})) as *mut c_void", ident).unwrap();
writeln!(w, "\tBox::into_raw(Box::new(Clone::clone(unsafe {{ &*(this_ptr as *const native{}) }}))) as *mut c_void", ident).unwrap();
writeln!(w, "}}").unwrap();
writeln!(w, "#[no_mangle]").unwrap();
writeln!(w, "/// Creates a copy of the {}", ident).unwrap();
writeln!(w, "pub extern \"C\" fn {}_clone(orig: &{}) -> {} {{", ident, ident, ident).unwrap();
writeln!(w, "\torig.clone()").unwrap();
writeln!(w, "\tClone::clone(orig)").unwrap();
writeln!(w, "}}").unwrap();
} else if path_matches_nongeneric(&trait_path.1, &["FromStr"]) {
let mut err_opt = None;
Expand Down Expand Up @@ -2556,6 +2586,7 @@ fn main() {

// Write a few manually-defined types into the C++ header file
write_cpp_wrapper(&mut cpp_header_file, "Str", true, None);
write_cpp_wrapper(&mut cpp_header_file, "ECDSASignature", false, None);

// First parse the full crate's ASTs, caching them so that we can hold references to the AST
// objects in other datastructures:
Expand Down
47 changes: 36 additions & 11 deletions c-bindings-gen/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ pub fn single_ident_generic_path_to_ident(p: &syn::Path) -> Option<&syn::Ident>
} else { None }
}

pub fn path_matches_ignoring_generics(p: &syn::Path, exp: &[&str]) -> bool {
if p.segments.len() != exp.len() { return false; }
for (seg, e) in p.segments.iter().zip(exp.iter()) {
if &format!("{}", seg.ident) != *e { return false; }
}
true
}

pub fn path_matches_nongeneric(p: &syn::Path, exp: &[&str]) -> bool {
if p.segments.len() != exp.len() { return false; }
for (seg, e) in p.segments.iter().zip(exp.iter()) {
Expand Down Expand Up @@ -576,6 +584,7 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr
Self::insert_primitive(&mut imports, "bool");
Self::insert_primitive(&mut imports, "u128");
Self::insert_primitive(&mut imports, "i64");
Self::insert_primitive(&mut imports, "i32");
Self::insert_primitive(&mut imports, "f64");
Self::insert_primitive(&mut imports, "u64");
Self::insert_primitive(&mut imports, "u32");
Expand Down Expand Up @@ -917,6 +926,11 @@ fn initial_clonable_types() -> HashSet<String> {
// `write_c_mangled_container_path_intern` (which will add it here too), so we have to manually
// add it on startup.
res.insert("crate::c_types::derived::CVec_u8Z".to_owned());

// write_c_type_intern writes the empty string for the empty tuple. In order to ensure
// COption_NoneZ is marked clonable, we have to support "cloning" "".
res.insert("".to_owned());

res
}

Expand Down Expand Up @@ -1037,6 +1051,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
match full_path {
"bool" => true,
"i64" => true,
"i32" => true,
"f64" => true,
"u64" => true,
"u32" => true,
Expand Down Expand Up @@ -1110,7 +1125,9 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
"bitcoin::secp256k1::Scalar" if !is_ref => Some("crate::c_types::BigEndianScalar"),
"bitcoin::secp256k1::ecdh::SharedSecret" if !is_ref => Some("crate::c_types::ThirtyTwoBytes"),

"bitcoin::amount::Amount" => Some("u64"),
"bitcoin::Amount"|"bitcoin::amount::Amount" => Some("u64"),
"bitcoin::Weight" => Some("u64"),
"bitcoin::Sequence" => Some("u32"),

"bitcoin::script::Script"|"bitcoin::Script" => Some("crate::c_types::u8slice"),
"bitcoin::script::ScriptBuf"|"bitcoin::ScriptBuf" => Some("crate::c_types::derived::CVec_u8Z"),
Expand Down Expand Up @@ -1160,7 +1177,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
|"lightning::sign::KeyMaterial"|"lightning::chain::ClaimId"
if !is_ref => Some("crate::c_types::ThirtyTwoBytes"),

"lightning::io::Read" => Some("crate::c_types::u8slice"),
"lightning::util::ser::LengthLimitedRead"|"lightning::io::Read" => Some("crate::c_types::u8slice"),

_ => None,
}
Expand Down Expand Up @@ -1230,7 +1247,9 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
"bitcoin::secp256k1::Scalar" if !is_ref => Some(""),
"bitcoin::secp256k1::ecdh::SharedSecret" if !is_ref => Some("::bitcoin::secp256k1::ecdh::SharedSecret::from_bytes("),

"bitcoin::amount::Amount" => Some("::bitcoin::amount::Amount::from_sat("),
"bitcoin::Amount"|"bitcoin::amount::Amount" => Some("::bitcoin::amount::Amount::from_sat("),
"bitcoin::Weight" => Some("::bitcoin::Weight::from_wu("),
"bitcoin::Sequence" => Some("::bitcoin::Sequence("),

"bitcoin::script::Script"|"bitcoin::Script" => Some("::bitcoin::script::Script::from_bytes("),
"bitcoin::script::ScriptBuf"|"bitcoin::ScriptBuf" => Some("::bitcoin::script::ScriptBuf::from("),
Expand Down Expand Up @@ -1287,7 +1306,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
"lightning::chain::ClaimId" if is_ref=> Some("&::lightning::chain::ClaimId( unsafe { *"),

// List of traits we map (possibly during processing of other files):
"lightning::io::Read" => Some("&mut "),
"lightning::util::ser::LengthLimitedRead"|"lightning::io::Read" => Some("&mut "),

_ => None,
}.map(|s| s.to_owned())
Expand Down Expand Up @@ -1349,7 +1368,9 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
"bitcoin::secp256k1::Scalar" => Some(".into_rust()"),
"bitcoin::secp256k1::ecdh::SharedSecret" if !is_ref => Some(".data)"),

"bitcoin::amount::Amount" => Some(")"),
"bitcoin::Amount"|"bitcoin::amount::Amount" => Some(")"),
"bitcoin::Weight" => Some(")"),
"bitcoin::Sequence" => Some(")"),

"bitcoin::script::Script"|"bitcoin::Script" => Some(".to_slice())"),
"bitcoin::script::ScriptBuf"|"bitcoin::ScriptBuf" => Some(".into_rust())"),
Expand Down Expand Up @@ -1399,7 +1420,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
if is_ref => Some(" })"),

// List of traits we map (possibly during processing of other files):
"lightning::io::Read" => Some(".to_reader()"),
"lightning::util::ser::LengthLimitedRead"|"lightning::io::Read" => Some(".to_slice()"),

_ => None,
}.map(|s| s.to_owned())
Expand Down Expand Up @@ -1481,7 +1502,9 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
"bitcoin::secp256k1::Scalar" if !is_ref => Some("crate::c_types::BigEndianScalar::from_rust(&"),
"bitcoin::secp256k1::ecdh::SharedSecret" if !is_ref => Some("crate::c_types::ThirtyTwoBytes { data: "),

"bitcoin::amount::Amount" => Some(""),
"bitcoin::Amount"|"bitcoin::amount::Amount" => Some(""),
"bitcoin::Weight" => Some(""),
"bitcoin::Sequence" => Some(""),

"bitcoin::script::Script"|"bitcoin::Script" => Some("crate::c_types::u8slice::from_slice("),
"bitcoin::script::ScriptBuf"|"bitcoin::ScriptBuf" => Some(""),
Expand Down Expand Up @@ -1530,7 +1553,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
|"lightning::sign::KeyMaterial"|"lightning::chain::ClaimId"
if !is_ref => Some("crate::c_types::ThirtyTwoBytes { data: "),

"lightning::io::Read" => Some("crate::c_types::u8slice::from_vec(&crate::c_types::reader_to_vec("),
"lightning::util::ser::LengthLimitedRead"|"lightning::io::Read" => Some("crate::c_types::u8slice::from_vec(&crate::c_types::reader_to_vec("),

_ => None,
}.map(|s| s.to_owned())
Expand Down Expand Up @@ -1594,7 +1617,9 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
"bitcoin::secp256k1::Scalar" if !is_ref => Some(")"),
"bitcoin::secp256k1::ecdh::SharedSecret" if !is_ref => Some(".secret_bytes() }"),

"bitcoin::amount::Amount" => Some(".to_sat()"),
"bitcoin::Amount"|"bitcoin::amount::Amount" => Some(".to_sat()"),
"bitcoin::Weight" => Some(".to_wu()"),
"bitcoin::Sequence" => Some(".0"),

"bitcoin::script::Script"|"bitcoin::Script" => Some(".as_ref())"),
"bitcoin::script::ScriptBuf"|"bitcoin::ScriptBuf" if is_ref => Some(".as_bytes().to_vec().into()"),
Expand Down Expand Up @@ -1640,7 +1665,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
|"lightning::sign::KeyMaterial"|"lightning::chain::ClaimId"
if !is_ref => Some(".0 }"),

"lightning::io::Read" => Some("))"),
"lightning::util::ser::LengthLimitedRead"|"lightning::io::Read" => Some("))"),

_ => None,
}.map(|s| s.to_owned())
Expand All @@ -1661,7 +1686,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
/// TODO: We should never need to use this!
fn real_rust_type_mapping<'equiv>(&self, thing: &'equiv str) -> &'equiv str {
match thing {
"lightning::io::Read" => "crate::c_types::io::Read",
"lightning::util::ser::LengthLimitedRead"|"lightning::io::Read" => "crate::c_types::io::Read",
_ => thing,
}
}
Expand Down
4 changes: 2 additions & 2 deletions genbindings.sh
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ static inline const char* check_get_ldk_version() {
// Version mismatch, we don't know what we're running!
return 0;
}
Str_free(bin_ver);
return _LDK_HEADER_VER;
}
static inline const char* check_get_ldk_bindings_version() {
Expand All @@ -145,6 +146,7 @@ static inline const char* check_get_ldk_bindings_version() {
// Version mismatch, we don't know what we're running!
return 0;
}
Str_free(bin_ver);
return _LDK_C_BINDINGS_HEADER_VER;
}
#endif /* _LDK_HEADER_VER */
Expand Down Expand Up @@ -207,7 +209,6 @@ if [ "$2" = "true" ]; then
add_crate "lightning-background-processor" "lightning_background_processor" --features=std,lightning/std
add_crate "lightning-invoice" "lightning_invoice" --features=std
add_crate "lightning-rapid-gossip-sync" "lightning_rapid_gossip_sync" --features=std,lightning/std
add_crate "lightning-liquidity" "lightning_liquidity" --features=std,lightning/std
CARGO_BUILD_ARGS="--features=std"
else
add_crate lightning lightning --features=dnssec
Expand All @@ -216,7 +217,6 @@ else
add_crate "lightning-background-processor" "lightning_background_processor"
add_crate "lightning-rapid-gossip-sync" "lightning_rapid_gossip_sync"
add_crate "lightning-invoice" "lightning_invoice"
add_crate "lightning-liquidity" "lightning_liquidity"
CARGO_BUILD_ARGS="--features=no-std"
fi

Expand Down
Loading
Loading