diff --git a/Cargo.lock b/Cargo.lock index 539df4a08..70da9d14a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -38,6 +38,11 @@ dependencies = [ "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ascii" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "assert_matches" version = "1.3.0" @@ -175,6 +180,11 @@ name = "cc" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "cfg-if" version = "0.1.5" @@ -239,6 +249,15 @@ dependencies = [ "cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "combine" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ascii 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "common-types" version = "0.1.0" @@ -1353,6 +1372,24 @@ name = "itoa" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "jni" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cesu8 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "combine 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jni-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "journaldb" version = "0.2.0" @@ -1965,6 +2002,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "parity-clib" version = "1.12.0" dependencies = [ + "jni 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "panic_hook 0.1.0", "parity-ethereum 2.1.0", ] @@ -2885,6 +2923,14 @@ name = "safemem" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "same-file" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "scoped-tls" version = "0.1.2" @@ -3686,6 +3732,16 @@ name = "void" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "walkdir" +version = "2.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "same-file 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "want" version = "0.0.4" @@ -3856,6 +3912,7 @@ dependencies = [ "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum app_dirs 1.2.1 (git+https://github.com/paritytech/app-dirs-rs)" = "" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" +"checksum ascii 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae7d751998c189c1d4468cf0a39bb2eae052a9c58d50ebb3b9591ee3813ad50" "checksum assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7deb0a829ca7bcfaf5da70b073a8d128619259a7be8216a355e23f00763059e5" "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" "checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a" @@ -3873,12 +3930,14 @@ dependencies = [ "checksum byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "90492c5858dd7d2e78691cfb89f90d273a2800fc11d98f60786e5d87e2f83781" "checksum bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e178b8e0e239e844b083d5a0d4a156b2654e67f9f80144d48398fcd736a24fb8" "checksum cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "4a6007c146fdd28d4512a794b07ffe9d8e89e6bf86e2e0c4ddff2e1fb54a0007" +"checksum cesu8 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" "checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3" "checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" "checksum cid 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d85ee025368e69063c420cbb2ed9f852cb03a5e69b73be021e65726ce03585b6" "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "704fbf3bb5149daab0afb255dbea24a1f08d2f4099cedb9baab6d470d4c5eefb" +"checksum combine 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1645a65a99c7c8d345761f4b75a6ffe5be3b3b27a93ee731fccc5050ba6be97c" "checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" "checksum crossbeam-deque 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3486aefc4c0487b9cb52372c97df0a48b8c249514af1ee99703bf70d2f2ceda1" @@ -3937,6 +3996,8 @@ dependencies = [ "checksum ipnetwork 0.12.8 (registry+https://github.com/rust-lang/crates.io-index)" = "70783119ac90828aaba91eae39db32c6c1b8838deea3637e5238efa0130801ab" "checksum itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4833d6978da405305126af4ac88569b5d71ff758581ce5a987dbfa3755f694fc" "checksum itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5adb58558dcd1d786b5f0bd15f3226ee23486e24b7b58304b60f64dc68e62606" +"checksum jni 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5479b540809575c4d6e3e68be5cdc33e03e0ab3d2108479a65d0374f2e82c1b9" +"checksum jni-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" "checksum jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)" = "" "checksum jsonrpc-http-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)" = "" "checksum jsonrpc-ipc-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)" = "" @@ -4059,6 +4120,7 @@ dependencies = [ "checksum rustls 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc9f2e05fd6a3ce1530cd5dbcc553d2f94d7749fe3e4f5b443668eddd842889e" "checksum ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7153dd96dade874ab973e098cb62fcdbb89a03682e46b144fd09550998d4a4a7" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" +"checksum same-file 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "10f7794e2fda7f594866840e95f5c5962e886e228e68b6505885811a94dd728c" "checksum scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum sct 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1137b767bbe1c4d30656993bdd97422ed41255d9400b105d735f8c7d9e800632" @@ -4147,6 +4209,7 @@ dependencies = [ "checksum vergen 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c3365f36c57e5df714a34be40902b27a992eeddb9996eca52d0584611cf885d" "checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +"checksum walkdir 2.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "af464bc7be7b785c7ac72e266a6b67c4c9070155606f51655a650a6686204e35" "checksum want 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a05d9d966753fa4b5c8db73fcab5eed4549cfe0e1e4e66911e5564a0085c35d1" "checksum wasmi 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b4a6d379e9332b1b1f52c5a87f2481c85c7c931d8ec411963dfb8f26b1ec1e3" "checksum webpki 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e1622384bcb5458c6a3e3fa572f53ea8fef1cc85e535a2983dea87e9154fac2" diff --git a/parity-clib/Cargo.toml b/parity-clib/Cargo.toml index 32ddf0ecd..e603ca2de 100644 --- a/parity-clib/Cargo.toml +++ b/parity-clib/Cargo.toml @@ -12,6 +12,7 @@ crate-type = ["cdylib", "staticlib"] [dependencies] panic_hook = { path = "../util/panic_hook" } parity-ethereum = { path = "../", default-features = false } +jni = { version = "0.10.1", optional = true } [features] default = [] diff --git a/parity-clib/Parity.java b/parity-clib/Parity.java new file mode 100644 index 000000000..7e70917ae --- /dev/null +++ b/parity-clib/Parity.java @@ -0,0 +1,63 @@ +// Copyright 2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +package io.parity.ethereum; + +/** + * Interface to the Parity client. + */ +public class Parity { + /** + * Starts the Parity client with the CLI options passed as an array of strings. + * + * Each space-delimited option corresponds to an array entry. + * For example: `["--port", "12345"]` + * + * @param options The CLI options to start Parity with + */ + public Parity(String[] options) { + long config = configFromCli(options); + inner = build(config); + } + + /** Performs a synchronous RPC query. + * + * Note that this will block the current thread until the query is finished. You are + * encouraged to create a background thread if you don't want to block. + * + * @param query The JSON-encoded RPC query to perform + * @return A JSON-encoded result + */ + public String rpcQuery(String query) { + return rpcQueryNative(inner, query); + } + + @Override + protected void finalize​() { + destroy(inner); + } + + static { + System.loadLibrary("parity"); + } + + private static native long configFromCli(String[] cliOptions); + private static native long build(long config); + private static native void destroy(long inner); + private static native String rpcQueryNative(long inner, String rpc); + + private long inner; +} diff --git a/parity-clib/src/lib.rs b/parity-clib/src/lib.rs index ad0c8a032..28b212acd 100644 --- a/parity-clib/src/lib.rs +++ b/parity-clib/src/lib.rs @@ -17,6 +17,8 @@ //! Note that all the structs and functions here are documented in `parity.h`, to avoid //! duplicating documentation. +#[cfg(feature = "jni")] +extern crate jni; extern crate parity_ethereum; extern crate panic_hook; @@ -26,6 +28,11 @@ use std::ptr; use std::slice; use std::str; +#[cfg(feature = "jni")] +use std::mem; +#[cfg(feature = "jni")] +use jni::{JNIEnv, objects::JClass, objects::JString, sys::jlong, sys::jobjectArray}; + #[repr(C)] pub struct ParityParams { pub configuration: *mut c_void, @@ -117,7 +124,7 @@ pub unsafe extern fn parity_destroy(client: *mut c_void) { } #[no_mangle] -pub unsafe extern fn parity_rpc(client: *mut c_void, query: *const char, len: usize, out_str: *mut c_char, out_len: *mut usize) -> c_int { +pub unsafe extern fn parity_rpc(client: *mut c_void, query: *const c_char, len: usize, out_str: *mut c_char, out_len: *mut usize) -> c_int { panic::catch_unwind(|| { let client: &mut parity_ethereum::RunningClient = &mut *(client as *mut parity_ethereum::RunningClient); @@ -163,3 +170,98 @@ impl CallbackStr { } } } + +#[cfg(feature = "jni")] +#[no_mangle] +pub unsafe extern "system" fn Java_io_parity_ethereum_Parity_configFromCli(env: JNIEnv, _: JClass, cli: jobjectArray) -> jlong { + let cli_len = env.get_array_length(cli).expect("invalid Java bindings"); + + let mut jni_strings = Vec::with_capacity(cli_len as usize); + let mut opts = Vec::with_capacity(cli_len as usize); + let mut opts_lens = Vec::with_capacity(cli_len as usize); + + for n in 0 .. cli_len { + let elem = env.get_object_array_element(cli, n).expect("invalid Java bindings"); + let elem_str: JString = elem.into(); + match env.get_string(elem_str) { + Ok(s) => { + opts.push(s.as_ptr()); + opts_lens.push(s.to_bytes().len()); + jni_strings.push(s); + }, + Err(err) => { + let _ = env.throw_new("java/lang/Exception", err.to_string()); + 0 + } + }; + } + + let mut out = ptr::null_mut(); + match parity_config_from_cli(opts.as_ptr(), opts_lens.as_ptr(), cli_len as usize, &mut out) { + 0 => out as usize as jlong, + _ => { + let _ = env.throw_new("java/lang/Exception", "failed to create config object"); + 0 + }, + } +} + +#[cfg(feature = "jni")] +#[no_mangle] +pub unsafe extern "system" fn Java_io_parity_ethereum_Parity_build(env: JNIEnv, _: JClass, config: jlong) -> jlong { + let params = ParityParams { + configuration: config as usize as *mut c_void, + .. mem::zeroed() + }; + + let mut out = ptr::null_mut(); + match parity_start(¶ms, &mut out) { + 0 => out as usize as jlong, + _ => { + let _ = env.throw_new("java/lang/Exception", "failed to start Parity"); + 0 + }, + } +} + +#[cfg(feature = "jni")] +#[no_mangle] +pub unsafe extern "system" fn Java_io_parity_ethereum_Parity_destroy(_env: JNIEnv, _: JClass, parity: jlong) { + let parity = parity as usize as *mut c_void; + parity_destroy(parity); +} + +#[cfg(feature = "jni")] +#[no_mangle] +pub unsafe extern "system" fn Java_io_parity_ethereum_Parity_rpcQueryNative<'a>(env: JNIEnv<'a>, _: JClass, parity: jlong, rpc: JString) -> JString<'a> { + let parity = parity as usize as *mut c_void; + + let rpc = match env.get_string(rpc) { + Ok(s) => s, + Err(err) => { + let _ = env.throw_new("java/lang/Exception", err.to_string()); + return env.new_string("").expect("Creating an empty string never fails"); + }, + }; + + let mut out_len = 255; + let mut out = [0u8; 256]; + + match parity_rpc(parity, rpc.as_ptr(), rpc.to_bytes().len(), out.as_mut_ptr() as *mut c_char, &mut out_len) { + 0 => (), + _ => { + let _ = env.throw_new("java/lang/Exception", "failed to perform RPC query"); + return env.new_string("").expect("Creating an empty string never fails"); + }, + } + + let out = str::from_utf8(&out[..out_len]) + .expect("parity always generates an UTF-8 RPC response"); + match env.new_string(out) { + Ok(s) => s, + Err(err) => { + let _ = env.throw_new("java/lang/Exception", err.to_string()); + return env.new_string("").expect("Creating an empty string never fails"); + } + } +}