From 8f0b95de59085e4b4ab3f16ed20bac0f28a9fc3d Mon Sep 17 00:00:00 2001 From: Hanh Date: Wed, 11 Sep 2024 11:28:46 +1000 Subject: [PATCH] ffi wip --- Cargo.lock | 168 ++++++++++++++++++++++++++++++++++++----- Cargo.toml | 4 +- lwd-warp | 2 +- warp-macros/Cargo.toml | 15 ++++ warp-macros/src/lib.rs | 153 +++++++++++++++++++++++++++++++++++++ zcash-warp | 2 +- 6 files changed, 321 insertions(+), 23 deletions(-) create mode 100644 warp-macros/Cargo.toml create mode 100644 warp-macros/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index ace6a35..4e78db4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -617,6 +617,25 @@ dependencies = [ "cipher", ] +[[package]] +name = "cbindgen" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fce8dd7fcfcbf3a0a87d8f515194b49d6135acab73e18bd380d1d93bb1a15eb" +dependencies = [ + "clap", + "heck 0.4.1", + "indexmap 2.5.0", + "log", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn 2.0.77", + "tempfile", + "toml 0.8.19", +] + [[package]] name = "cc" version = "1.1.15" @@ -740,7 +759,7 @@ version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" dependencies = [ - "heck", + "heck 0.5.0", "proc-macro2", "quote", "syn 2.0.77", @@ -1537,6 +1556,12 @@ dependencies = [ "hashbrown 0.14.5", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "heck" version = "0.5.0" @@ -1903,6 +1928,15 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.12.1" @@ -2062,7 +2096,7 @@ dependencies = [ "hex", "lazy_static", "parking_lot", - "prost", + "prost 0.13.2", "r2d2", "r2d2_sqlite", "rusqlite", @@ -2071,7 +2105,7 @@ dependencies = [ "tokio", "tokio-stream", "tonic", - "tonic-build", + "tonic-build 0.8.4", "tonic-reflection", "tracing", "tracing-subscriber", @@ -2195,6 +2229,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "multimap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" + [[package]] name = "multimap" version = "0.10.0" @@ -2554,6 +2594,16 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "prettyplease" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +dependencies = [ + "proc-macro2", + "syn 1.0.109", +] + [[package]] name = "prettyplease" version = "0.2.22" @@ -2630,6 +2680,16 @@ dependencies = [ "unarray", ] +[[package]] +name = "prost" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +dependencies = [ + "bytes", + "prost-derive 0.11.9", +] + [[package]] name = "prost" version = "0.13.2" @@ -2637,7 +2697,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b2ecbe40f08db5c006b5764a2645f7f3f141ce756412ac9e1dd6087e6d32995" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.13.2", +] + +[[package]] +name = "prost-build" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" +dependencies = [ + "bytes", + "heck 0.4.1", + "itertools 0.10.5", + "lazy_static", + "log", + "multimap 0.8.3", + "petgraph", + "prettyplease 0.1.25", + "prost 0.11.9", + "prost-types 0.11.9", + "regex", + "syn 1.0.109", + "tempfile", + "which", ] [[package]] @@ -2647,20 +2729,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8650aabb6c35b860610e9cff5dc1af886c9e25073b7b1712a68972af4281302" dependencies = [ "bytes", - "heck", + "heck 0.5.0", "itertools 0.13.0", "log", - "multimap", + "multimap 0.10.0", "once_cell", "petgraph", - "prettyplease", - "prost", - "prost-types", + "prettyplease 0.2.22", + "prost 0.13.2", + "prost-types 0.13.2", "regex", "syn 2.0.77", "tempfile", ] +[[package]] +name = "prost-derive" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +dependencies = [ + "anyhow", + "itertools 0.10.5", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "prost-derive" version = "0.13.2" @@ -2674,13 +2769,22 @@ dependencies = [ "syn 2.0.77", ] +[[package]] +name = "prost-types" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" +dependencies = [ + "prost 0.11.9", +] + [[package]] name = "prost-types" version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60caa6738c7369b940c3d49246a8d1749323674c65cb13010134f5c9bad5b519" dependencies = [ - "prost", + "prost 0.13.2", ] [[package]] @@ -3568,7 +3672,7 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ - "heck", + "heck 0.5.0", "proc-macro2", "quote", "rustversion", @@ -3594,6 +3698,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", + "quote", "unicode-ident", ] @@ -3881,7 +3986,7 @@ dependencies = [ "hyper-util", "percent-encoding", "pin-project", - "prost", + "prost 0.13.2", "rustls-native-certs", "rustls-pemfile", "socket2", @@ -3894,15 +3999,28 @@ dependencies = [ "tracing", ] +[[package]] +name = "tonic-build" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf5e9b9c0f7e0a7c027dcfaba7b2c60816c7049171f679d99ee2ff65d0de8c4" +dependencies = [ + "prettyplease 0.1.25", + "proc-macro2", + "prost-build 0.11.9", + "quote", + "syn 1.0.109", +] + [[package]] name = "tonic-build" version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe4ee8877250136bd7e3d2331632810a4df4ea5e004656990d8d66d2f5ee8a67" dependencies = [ - "prettyplease", + "prettyplease 0.2.22", "proc-macro2", - "prost-build", + "prost-build 0.13.2", "quote", "syn 2.0.77", ] @@ -3913,8 +4031,8 @@ version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b56b874eedb04f89907573b408eab1e87c1c1dce43aac6ad63742f57faa99ff" dependencies = [ - "prost", - "prost-types", + "prost 0.13.2", + "prost-types 0.13.2", "tokio", "tokio-stream", "tonic", @@ -4222,6 +4340,14 @@ dependencies = [ "try-lock", ] +[[package]] +name = "warp-macros" +version = "0.1.0" +dependencies = [ + "quote", + "syn 2.0.77", +] + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" @@ -4541,6 +4667,7 @@ dependencies = [ "bech32 0.11.0", "bincode", "blake2b_simd", + "cbindgen", "chacha20", "chrono", "clap", @@ -4558,7 +4685,7 @@ dependencies = [ "lazy_static", "orchard", "parking_lot", - "prost", + "prost 0.13.2", "r2d2", "r2d2_sqlite", "rand 0.8.5", @@ -4580,9 +4707,10 @@ dependencies = [ "tiny-hderive", "tokio", "tonic", - "tonic-build", + "tonic-build 0.12.2", "tracing", "tracing-subscriber", + "warp-macros", "zcash_address", "zcash_client_backend", "zcash_encoding", @@ -4627,7 +4755,7 @@ dependencies = [ "nonempty", "orchard", "percent-encoding", - "prost", + "prost 0.13.2", "rand_core 0.6.4", "rayon", "sapling-crypto", @@ -4635,7 +4763,7 @@ dependencies = [ "shardtree", "subtle 2.6.1", "time", - "tonic-build", + "tonic-build 0.12.2", "tracing", "which", "zcash_address", diff --git a/Cargo.toml b/Cargo.toml index ebee404..af699ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,11 @@ [workspace] members = [ "zcash-warp", - "lwd-warp" + "lwd-warp", + "warp-macros" ] exclude = [ + "librustzcash", "orchard" ] resolver = "2" diff --git a/lwd-warp b/lwd-warp index 3a8fa44..f2bb677 160000 --- a/lwd-warp +++ b/lwd-warp @@ -1 +1 @@ -Subproject commit 3a8fa443dcff1cf97627f07277775c4cf5858de0 +Subproject commit f2bb6774a33f9628014524cc6146434ab432ff26 diff --git a/warp-macros/Cargo.toml b/warp-macros/Cargo.toml new file mode 100644 index 0000000..285f360 --- /dev/null +++ b/warp-macros/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "warp-macros" +version = "0.1.0" +edition.workspace = true +rust-version.workspace = true +categories.workspace = true +license.workspace = true +repository.workspace = true + +[lib] +proc-macro = true + +[dependencies] +quote = { version = "1.0.37", features = [ "proc-macro" ] } +syn = { version = "2.0.77", features = [ "full" ] } diff --git a/warp-macros/src/lib.rs b/warp-macros/src/lib.rs new file mode 100644 index 0000000..fdd35a3 --- /dev/null +++ b/warp-macros/src/lib.rs @@ -0,0 +1,153 @@ +extern crate proc_macro; +use proc_macro::TokenStream; +use quote::quote; +use syn::{ + parse2, parse_macro_input, FnArg, GenericArgument, Ident, ItemFn, Pat, PathArguments, ReturnType, Signature, Type +}; + +#[proc_macro_attribute] +pub fn c_export(_attr: TokenStream, item: TokenStream) -> TokenStream { + let input = parse_macro_input!(item as ItemFn); + let sig = &input.sig; + + let Signature { + ident, + inputs, + output, + .. + } = sig; + + let ReturnType::Type(_, retype) = output else { + panic!() + }; + let Type::Path(type_path) = retype.as_ref() else { + panic!() + }; + let path = &type_path.path; + assert_eq!(path.segments[0].ident.to_string(), "Result"); + let PathArguments::AngleBracketed(type_arg) = &path.segments[0].arguments else { + panic!() + }; + let GenericArgument::Type(result_type) = &type_arg.args[0] else { + panic!() + }; + let Type::Path(result_type) = result_type else { + panic!() + }; + let result_type = result_type.path.get_ident().unwrap(); + let map_result = match result_type.to_string().as_str() { + "String" => quote! { + map_result_string(res) + }, + "VecBytes" => quote! { + map_result_bytes(res) + }, + _ => quote! { + map_result(res) + }, + }; + + let ItemFn { vis, block, .. } = &input; + let mut wrapped_fnargs = vec![]; + let mut str_convs = vec![]; + let mut has_network = false; + let mut has_connection = false; + let mut has_client = false; + for input in inputs.iter() { + if let FnArg::Typed(pat) = input { + if let Pat::Ident(param) = pat.pat.as_ref() { + let ident = ¶m.ident; + let name = ident.to_string(); + match name.as_str() { + "network" => { + has_network = true; + continue; + } + "connection" => { + has_connection = true; + continue; + } + "client" => { + has_client = true; + continue; + } + _ => {} + } + let p = pat.ty.as_ref(); + let s = quote! { #p }.to_string(); + if s == "& str" { + str_convs.push(quote! { + let #ident = unsafe { CStr::from_ptr(#ident).to_string_lossy() }; + let #ident = &#ident; + }); + let input = quote! { + #ident: *mut c_char + }; + let input = parse2::(input).unwrap(); + wrapped_fnargs.push(input); + continue; + } + } + } + wrapped_fnargs.push(input.clone()); + } + + let network = if has_network { + quote! { + let network = &coin.network; + } + } else { + quote! {} + }; + let connection = if has_connection { + quote! { + let connection = &coin.connection(); + } + } else { + quote! {} + }; + let client = if has_client { + quote! { + let mut client = coin.connect_lwd().await?; + let client = &mut client; + } + } else { + quote! {} + }; + + let args = inputs + .iter() + .map(|arg| { + let FnArg::Typed(pat_type) = arg else { + panic!(); + }; + let syn::Pat::Ident(pat_ident) = &*pat_type.pat else { + panic!(); + }; + &pat_ident.ident + }) + .collect::>(); + + let wrapper = Ident::new(&format!("c_{}", ident), ident.span()); + + let res = quote! { + #[no_mangle] + #[tokio::main] + pub async extern "C" fn #wrapper(coin: u8, #(#wrapped_fnargs),*) -> CResult<#result_type> { + let res = async { + let coin = COINS[coin as usize].lock(); + #network + #connection + #client + #(#str_convs),* + #ident(#(#args),*).await + }; + let res = res.await; + #map_result + } + + #vis async fn #ident(#inputs) #output #block + }; + + res.into() +} diff --git a/zcash-warp b/zcash-warp index 825e5cf..cdbd500 160000 --- a/zcash-warp +++ b/zcash-warp @@ -1 +1 @@ -Subproject commit 825e5cf42aeab0681fa3a19e24b5056ca95d2a20 +Subproject commit cdbd500197f83259a4dc567ec168d223c801c313