forked from iotaledger/iota-sdk-native-bindings
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request iotaledger#1 from iotaledger/add_native_library
Add native library
- Loading branch information
Showing
10 changed files
with
809 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# Created by https://www.toptal.com/developers/gitignore/api/rust,rust-analyzer | ||
# Edit at https://www.toptal.com/developers/gitignore?templates=rust,rust-analyzer | ||
|
||
### Rust ### | ||
# Generated by Cargo | ||
# will have compiled files and executables | ||
debug/ | ||
target/ | ||
|
||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries | ||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html | ||
Cargo.lock | ||
|
||
# These are backup files generated by rustfmt | ||
**/*.rs.bk | ||
|
||
# MSVC Windows builds of rustc generate these, which store debugging information | ||
*.pdb | ||
|
||
### rust-analyzer ### | ||
# Can be generated by other build systems other than cargo (ex: bazelbuild/rust_rules) | ||
rust-project.json | ||
|
||
|
||
# End of https://www.toptal.com/developers/gitignore/api/rust,rust-analyzer |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
[package] | ||
name = "iota-sdk-native" | ||
version = "0.1.0" | ||
authors = [ "IOTA Stiftung" ] | ||
edition = "2021" | ||
description = "Native wrapper for the IOTA SDK library" | ||
documentation = "https://wiki.iota.org/iota-sdk/welcome" | ||
homepage = "https://www.iota.org/" | ||
repository = "https://github.com/iotaledger/iota-sdk" | ||
license = "Apache-2.0" | ||
keywords = [ "iota", "client", "wallet", "transaction", "native" ] | ||
categories = [ "cryptography::cryptocurrencies" ] | ||
publish = false | ||
|
||
[lib] | ||
name = "iota_sdk_native" | ||
crate-type = [ "cdylib" ] | ||
doc = false | ||
|
||
[features] | ||
default = ["std"] | ||
std = ["zeroize/std"] | ||
|
||
[dependencies] | ||
iota-sdk-bindings-core = { git = "https://github.com/iotaledger/iota-sdk.git", branch = "develop", default-features = false, features = [ | ||
"events", | ||
"rocksdb", | ||
"ledger_nano", | ||
"storage", | ||
"stronghold", | ||
"private_key_secret_manager" | ||
] } | ||
|
||
futures = { version = "0.3.28", default-features = false } | ||
once_cell = { version = "1.18.0", default-features = false } | ||
serde_json = { version = "1.0.107", default-features = false } | ||
tokio = { version = "1.32.0", default-features = false } | ||
log = { version = "0.4.20", default-features = false } | ||
zeroize = { version = "1.6.0", default-features = false } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
#!/usr/bin/env bash | ||
set -euo pipefail | ||
|
||
cbindgen --crate iota-sdk-native --output headers/iota_sdk.h --lang c | ||
cbindgen --crate iota-sdk-native --output headers/iota_sdk.hpp --lang c++ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
#include <stdarg.h> | ||
#include <stdbool.h> | ||
#include <stdint.h> | ||
#include <stdlib.h> | ||
|
||
typedef struct Client Client; | ||
|
||
typedef struct SecretManager SecretManager; | ||
|
||
typedef struct Wallet Wallet; | ||
|
||
bool destroy_string(char *ptr); | ||
|
||
bool init_logger(const char *config_ptr); | ||
|
||
const char *call_utils_method(const char *config_ptr); | ||
|
||
const struct Client *create_client(const char *options_ptr); | ||
|
||
bool destroy_client(struct Client *client_ptr); | ||
|
||
const char *call_client_method(struct Client *client_ptr, char *method_ptr); | ||
|
||
const char *binding_get_last_error(void); | ||
|
||
const struct SecretManager *create_secret_manager(const char *options_ptr); | ||
|
||
bool destroy_secret_manager(struct SecretManager *secret_manager_ptr); | ||
|
||
const char *call_secret_manager_method(struct SecretManager *secret_manager, const char *method); | ||
|
||
bool destroy_wallet(struct Wallet *wallet_ptr); | ||
|
||
const struct Wallet *create_wallet(const char *options_ptr); | ||
|
||
const char *call_wallet_method(struct Wallet *wallet_ptr, const char *method_ptr); | ||
|
||
bool listen_wallet(struct Wallet *wallet_ptr, const char *events, void (*handler)(const char*)); | ||
|
||
const struct Client *get_client_from_wallet(struct Wallet *wallet_ptr); | ||
|
||
const struct SecretManager *get_secret_manager_from_wallet(struct Wallet *wallet_ptr); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
#include <cstdarg> | ||
#include <cstdint> | ||
#include <cstdlib> | ||
#include <ostream> | ||
#include <new> | ||
|
||
struct Client; | ||
|
||
struct SecretManager; | ||
|
||
struct Wallet; | ||
|
||
extern "C" { | ||
|
||
bool destroy_string(char *ptr); | ||
|
||
bool init_logger(const char *config_ptr); | ||
|
||
const char *call_utils_method(const char *config_ptr); | ||
|
||
const Client *create_client(const char *options_ptr); | ||
|
||
bool destroy_client(Client *client_ptr); | ||
|
||
const char *call_client_method(Client *client_ptr, char *method_ptr); | ||
|
||
const char *binding_get_last_error(); | ||
|
||
const SecretManager *create_secret_manager(const char *options_ptr); | ||
|
||
bool destroy_secret_manager(SecretManager *secret_manager_ptr); | ||
|
||
const char *call_secret_manager_method(SecretManager *secret_manager, const char *method); | ||
|
||
bool destroy_wallet(Wallet *wallet_ptr); | ||
|
||
const Wallet *create_wallet(const char *options_ptr); | ||
|
||
const char *call_wallet_method(Wallet *wallet_ptr, const char *method_ptr); | ||
|
||
bool listen_wallet(Wallet *wallet_ptr, const char *events, void (*handler)(const char*)); | ||
|
||
const Client *get_client_from_wallet(Wallet *wallet_ptr); | ||
|
||
const SecretManager *get_secret_manager_from_wallet(Wallet *wallet_ptr); | ||
|
||
} // extern "C" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
// Copyright 2023 IOTA Stiftung | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
use std::{ | ||
ffi::{c_char, CStr, CString}, | ||
ptr::null, | ||
}; | ||
|
||
use iota_sdk_bindings_core::{ | ||
call_client_method as rust_call_client_method, | ||
iota_sdk::client::{Client as RustClient, ClientBuilder}, | ||
ClientMethod, | ||
}; | ||
|
||
use crate::error::{set_last_error, Error, Result}; | ||
|
||
pub struct Client { | ||
pub client: RustClient, | ||
} | ||
|
||
unsafe fn internal_create_client(options_ptr: *const c_char) -> Result<*const Client> { | ||
let options_string = CStr::from_ptr(options_ptr).to_str().unwrap(); | ||
let runtime = tokio::runtime::Runtime::new()?; | ||
|
||
let client = runtime.block_on(async move { | ||
if options_string.is_empty() { | ||
return ClientBuilder::new().finish().await; | ||
} | ||
|
||
ClientBuilder::new().from_json(options_string)?.finish().await | ||
})?; | ||
|
||
let client_wrap = Client { client }; | ||
let client_ptr = Box::into_raw(Box::new(client_wrap)); | ||
|
||
Ok(client_ptr) | ||
} | ||
|
||
#[no_mangle] | ||
pub unsafe extern "C" fn create_client(options_ptr: *const c_char) -> *const Client { | ||
match internal_create_client(options_ptr) { | ||
Ok(v) => v, | ||
Err(e) => { | ||
set_last_error(e); | ||
null() | ||
} | ||
} | ||
} | ||
|
||
unsafe fn internal_destroy_client(client_ptr: *mut Client) -> Result<()> { | ||
log::debug!("[Rust] Client destroy called"); | ||
|
||
if client_ptr.is_null() { | ||
log::error!("[Rust] Client pointer was null!"); | ||
return Err(Error::from("pointer is null")); | ||
} | ||
|
||
let _ = Box::from_raw(client_ptr); | ||
|
||
log::debug!("[Rust] Destroyed client"); | ||
Ok(()) | ||
} | ||
|
||
#[no_mangle] | ||
pub unsafe extern "C" fn destroy_client(client_ptr: *mut Client) -> bool { | ||
match internal_destroy_client(client_ptr) { | ||
Ok(_) => true, | ||
Err(e) => { | ||
set_last_error(e); | ||
false | ||
} | ||
} | ||
} | ||
|
||
unsafe fn internal_call_client_method(client_ptr: *mut Client, method_ptr: *mut c_char) -> Result<*const c_char> { | ||
let method_str = CStr::from_ptr(method_ptr).to_str().unwrap(); | ||
|
||
let client = { | ||
assert!(!client_ptr.is_null()); | ||
&mut *client_ptr | ||
}; | ||
|
||
let method = serde_json::from_str::<ClientMethod>(method_str)?; | ||
let response = crate::block_on(async { rust_call_client_method(&client.client, method).await }); | ||
|
||
let response_string = serde_json::to_string(&response)?; | ||
let s = CString::new(response_string).unwrap(); | ||
|
||
Ok(s.into_raw()) | ||
} | ||
|
||
#[no_mangle] | ||
pub unsafe extern "C" fn call_client_method(client_ptr: *mut Client, method_ptr: *mut c_char) -> *const c_char { | ||
match internal_call_client_method(client_ptr, method_ptr) { | ||
Ok(v) => v, | ||
Err(e) => { | ||
set_last_error(e); | ||
null() | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
// Copyright 2023 IOTA Stiftung | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
use core::convert::{From, Infallible}; | ||
use std::{ | ||
cell::RefCell, | ||
ffi::{c_char, CString}, | ||
ptr, | ||
}; | ||
|
||
pub(crate) type Result<T> = std::result::Result<T, Error>; | ||
|
||
#[derive(Debug)] | ||
pub struct Error { | ||
pub error: String, | ||
} | ||
|
||
impl From<serde_json::Error> for Error { | ||
fn from(err: serde_json::Error) -> Self { | ||
Error { error: err.to_string() } | ||
} | ||
} | ||
|
||
impl From<std::io::Error> for Error { | ||
fn from(err: std::io::Error) -> Self { | ||
Error { error: err.to_string() } | ||
} | ||
} | ||
|
||
impl From<iota_sdk_bindings_core::iota_sdk::types::block::Error> for Error { | ||
fn from(err: iota_sdk_bindings_core::iota_sdk::types::block::Error) -> Self { | ||
Error { error: err.to_string() } | ||
} | ||
} | ||
|
||
impl From<iota_sdk_bindings_core::Error> for Error { | ||
fn from(err: iota_sdk_bindings_core::Error) -> Self { | ||
Error { error: err.to_string() } | ||
} | ||
} | ||
|
||
impl From<iota_sdk_bindings_core::iota_sdk::client::Error> for Error { | ||
fn from(err: iota_sdk_bindings_core::iota_sdk::client::Error) -> Self { | ||
Error { error: err.to_string() } | ||
} | ||
} | ||
|
||
impl From<iota_sdk_bindings_core::iota_sdk::wallet::Error> for Error { | ||
fn from(err: iota_sdk_bindings_core::iota_sdk::wallet::Error) -> Self { | ||
Error { error: err.to_string() } | ||
} | ||
} | ||
|
||
impl From<Infallible> for Error { | ||
fn from(err: Infallible) -> Self { | ||
Error { error: err.to_string() } | ||
} | ||
} | ||
|
||
impl From<&str> for Error { | ||
fn from(err: &str) -> Self { | ||
Self { error: err.to_string() } | ||
} | ||
} | ||
|
||
impl From<String> for Error { | ||
fn from(err: String) -> Self { | ||
Self { error: err } | ||
} | ||
} | ||
|
||
thread_local! { | ||
#[allow(clippy::box_collection)] | ||
static LAST_ERROR: RefCell<Option<Box<String>>> = RefCell::new(None); | ||
} | ||
|
||
pub fn set_last_error(err: Error) { | ||
LAST_ERROR.with(|prev| { | ||
*prev.borrow_mut() = Some(Box::new(err.error)); | ||
}); | ||
} | ||
|
||
#[no_mangle] | ||
pub unsafe extern "C" fn binding_get_last_error() -> *const c_char { | ||
let last_error = LAST_ERROR.with(|prev| prev.borrow_mut().take()); | ||
|
||
let last_error = match last_error { | ||
Some(err) => err, | ||
None => return ptr::null_mut(), | ||
}; | ||
|
||
let s = CString::new(last_error.to_string()).unwrap(); | ||
s.into_raw() | ||
} |
Oops, something went wrong.