Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Parity as a library #8412

Merged
merged 10 commits into from
May 9, 2018
Merged
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
8 changes: 7 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ ethcore-miner = { path = "miner" }
ethcore-network = { path = "util/network" }
ethcore-private-tx = { path = "ethcore/private-tx" }
ethcore-service = { path = "ethcore/service" }
ethcore-stratum = { path = "ethcore/stratum" }
ethcore-sync = { path = "ethcore/sync" }
ethcore-transaction = { path = "ethcore/transaction" }
ethereum-types = "0.3"
Expand Down Expand Up @@ -108,6 +107,9 @@ slow-blocks = ["ethcore/slow-blocks"]
secretstore = ["ethcore-secretstore"]
final = ["parity-version/final"]

[lib]
path = "parity/lib.rs"

[[bin]]
path = "parity/main.rs"
name = "parity"
Expand All @@ -130,6 +132,7 @@ members = [
"ethstore/cli",
"evmbin",
"miner",
"parity-clib",
"transaction-pool",
"whisper",
"whisper/cli",
Expand Down
19 changes: 19 additions & 0 deletions parity-clib-example/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
cmake_minimum_required(VERSION 3.5)
include(ExternalProject)

include_directories("${CMAKE_SOURCE_DIR}/../parity-clib")

add_executable(parity-example main.cpp)

ExternalProject_Add(
libparity
DOWNLOAD_COMMAND ""
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
COMMAND cargo build -p parity-clib # Note: use --release in a real project
BINARY_DIR "${CMAKE_SOURCE_DIR}/../target"
INSTALL_COMMAND ""
LOG_BUILD ON)

add_dependencies(parity-example libparity)
target_link_libraries(parity-example "${CMAKE_SOURCE_DIR}/../target/debug/libparity.so")
28 changes: 28 additions & 0 deletions parity-clib-example/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include <cstddef>
#include <unistd.h>
#include <parity.h>

void on_restart(void*, const char*, size_t) {}

int main() {
ParityParams cfg = { 0 };
cfg.on_client_restart_cb = on_restart;

const char* args[] = {"--light"};
size_t str_lens[] = {7};
if (parity_config_from_cli(args, str_lens, 1, &cfg.configuration) != 0) {
return 1;
}

void* parity;
if (parity_start(&cfg, &parity) != 0) {
return 1;
}

sleep(5);
if (parity != NULL) {
parity_destroy(parity);
}

return 0;
}
17 changes: 17 additions & 0 deletions parity-clib/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
description = "C bindings for the Parity Ethereum client"
name = "parity-clib"
version = "1.12.0"
license = "GPL-3.0"
authors = ["Parity Technologies <admin@parity.io>"]

[lib]
name = "parity"
crate-type = ["cdylib", "staticlib"]

[dependencies]
parity = { path = "../", default-features = false }

[features]
default = []
final = ["parity/final"]
93 changes: 93 additions & 0 deletions parity-clib/parity.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// 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 <http://www.gnu.org/licenses/>.

#ifndef _PARITY_H_INCLUDED_
#define _PARITY_H_INCLUDED_

#include <stddef.h>

/// Parameters to pass to `parity_start`.
struct ParityParams {
/// Configuration object, as handled by the `parity_config_*` functions.
/// Note that calling `parity_start` will destroy the configuration object (even on failure).
void *configuration;

/// Callback function to call when the client receives an RPC request to change its chain spec.
///
/// Will only be called if you enable the `--can-restart` flag.
///
/// The first parameter of the callback is the value of `on_client_restart_cb_custom`.
/// The second and third parameters of the callback are the string pointer and length.
void (*on_client_restart_cb)(void* custom, const char* new_chain, size_t new_chain_len);

/// Custom parameter passed to the `on_client_restart_cb` callback as first parameter.
void *on_client_restart_cb_custom;
};

#ifdef __cplusplus
extern "C" {
#endif

/// Builds a new configuration object by parsing a list of CLI arguments.
///
/// The first two parameters are string pointers and string lengths. They must have a length equal
/// to `len`. The strings don't need to be zero-terminated.
///
/// On success, the produced object will be written to the `void*` pointed by `out`.
///
/// Returns 0 on success, and non-zero on error.
///
/// # Example
///
/// ```no_run
/// void* cfg;
/// const char *args[] = {"--light", "--can-restart"};
/// size_t str_lens[] = {7, 13};
/// if (parity_config_from_cli(args, str_lens, 2, &cfg) != 0) {
/// return 1;
/// }
/// ```
///
int parity_config_from_cli(char const* const* args, size_t const* arg_lens, size_t len, void** out);

/// Destroys a configuration object created earlier.
///
/// **Important**: You probably don't need to call this function. Calling `parity_start` destroys
/// the configuration object as well (even on failure).
void parity_config_destroy(void* cfg);

/// Starts the parity client in background threads. Returns a pointer to a struct that represents
/// the running client. Can also return NULL if the execution completes instantly.
///
/// **Important**: The configuration object passed inside `cfg` is destroyed when you
/// call `parity_start` (even on failure).
///
/// On success, the produced object will be written to the `void*` pointed by `out`.
///
/// Returns 0 on success, and non-zero on error.
int parity_start(const ParityParams* params, void** out);

/// Destroys the parity client created with `parity_start`.
///
/// **Warning**: `parity_start` can return NULL if execution finished instantly, in which case you
/// must not call this function.
void parity_destroy(void* parity);

#ifdef __cplusplus
}
#endif

#endif // include guard
133 changes: 133 additions & 0 deletions parity-clib/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// 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 <http://www.gnu.org/licenses/>.

//! Note that all the structs and functions here are documented in `parity.h`, to avoid
//! duplicating documentation.

extern crate parity;

use std::os::raw::{c_char, c_void, c_int};
use std::panic;
use std::ptr;
use std::slice;

#[repr(C)]
pub struct ParityParams {
pub configuration: *mut c_void,
pub on_client_restart_cb: Option<extern "C" fn(*mut c_void, *const c_char, usize)>,
pub on_client_restart_cb_custom: *mut c_void,
}

#[no_mangle]
pub extern fn parity_config_from_cli(args: *const *const c_char, args_lens: *const usize, len: usize, output: *mut *mut c_void) -> c_int {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't pub unsafe extern "C" fn ... signature recommended for c api?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the official docs, no: https://doc.rust-lang.org/nomicon/ffi.html#calling-rust-code-from-c
I agree that this is really debatable, though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, i remember i was given this recommendation by Rust guys though
nvm

unsafe {
panic::catch_unwind(|| {
*output = ptr::null_mut();

let args = {
let arg_ptrs = slice::from_raw_parts(args, len);
let arg_lens = slice::from_raw_parts(args_lens, len);

let mut args = Vec::with_capacity(len + 1);
args.push("parity".to_owned());

for (&arg, &len) in arg_ptrs.iter().zip(arg_lens.iter()) {
let string = slice::from_raw_parts(arg as *const u8, len);
match String::from_utf8(string.to_owned()) {
Ok(a) => args.push(a),
Err(_) => return 1,
};
}

args
};

match parity::Configuration::parse_cli(&args) {
Ok(mut cfg) => {
// Always disable the auto-updater when used as a library.
cfg.args.arg_auto_update = "none".to_owned();

let cfg = Box::into_raw(Box::new(cfg));
*output = cfg as *mut _;
0
},
Err(_) => {
1
},
}
}).unwrap_or(1)
}
}

#[no_mangle]
pub extern fn parity_config_destroy(cfg: *mut c_void) {
unsafe {
let _ = panic::catch_unwind(|| {
let _cfg = Box::from_raw(cfg as *mut parity::Configuration);
});
}
}

#[no_mangle]
pub extern fn parity_start(cfg: *const ParityParams, output: *mut *mut c_void) -> c_int {
unsafe {
panic::catch_unwind(|| {
*output = ptr::null_mut();
let cfg: &ParityParams = &*cfg;

let config = Box::from_raw(cfg.configuration as *mut parity::Configuration);

let on_client_restart_cb = {
struct Cb(Option<extern "C" fn(*mut c_void, *const c_char, usize)>, *mut c_void);
unsafe impl Send for Cb {}
unsafe impl Sync for Cb {}
impl Cb {
fn call(&self, new_chain: String) {
if let Some(ref cb) = self.0 {
cb(self.1, new_chain.as_bytes().as_ptr() as *const _, new_chain.len())
}
}
}
let cb = Cb(cfg.on_client_restart_cb, cfg.on_client_restart_cb_custom);
move |new_chain: String| { cb.call(new_chain); }
};

let action = match parity::start(*config, on_client_restart_cb, || {}) {
Ok(action) => action,
Err(_) => return 1,
};

match action {
parity::ExecutionAction::Instant(Some(s)) => { println!("{}", s); 0 },
parity::ExecutionAction::Instant(None) => 0,
parity::ExecutionAction::Running(client) => {
*output = Box::into_raw(Box::<parity::RunningClient>::new(client)) as *mut c_void;
0
}
}
}).unwrap_or(1)
}
}

#[no_mangle]
pub extern fn parity_destroy(client: *mut c_void) {
unsafe {
let _ = panic::catch_unwind(|| {
let client = Box::from_raw(client as *mut parity::RunningClient);
client.shutdown();
});
}
}
7 changes: 0 additions & 7 deletions parity/blockchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ use params::{SpecType, Pruning, Switch, tracing_switch_to_bool, fatdb_switch_to_
use helpers::{to_client_config, execute_upgrades};
use dir::Directories;
use user_defaults::UserDefaults;
use fdlimit;
use ethcore_private_tx;
use db;

Expand Down Expand Up @@ -178,8 +177,6 @@ fn execute_import_light(cmd: ImportBlockchain) -> Result<(), String> {
// load user defaults
let user_defaults = UserDefaults::load(&user_defaults_path)?;

fdlimit::raise_fd_limit();

// select pruning algorithm
let algorithm = cmd.pruning.to_algorithm(&user_defaults);

Expand Down Expand Up @@ -327,8 +324,6 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> {
// load user defaults
let mut user_defaults = UserDefaults::load(&user_defaults_path)?;

fdlimit::raise_fd_limit();

// select pruning algorithm
let algorithm = cmd.pruning.to_algorithm(&user_defaults);

Expand Down Expand Up @@ -518,8 +513,6 @@ fn start_client(
// load user defaults
let user_defaults = UserDefaults::load(&user_defaults_path)?;

fdlimit::raise_fd_limit();

// select pruning algorithm
let algorithm = pruning.to_algorithm(&user_defaults);

Expand Down
1 change: 1 addition & 0 deletions parity/cli/usage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ macro_rules! usage {
}
}

/// Parsed command line arguments.
#[derive(Debug, PartialEq)]
pub struct Args {
$(
Expand Down
Loading