zcash-sync/src/api/dart_ffi.rs

526 lines
14 KiB
Rust
Raw Normal View History

2022-06-08 05:48:16 -07:00
use crate::coinconfig::{init_coin, CoinConfig};
2022-06-10 22:40:32 -07:00
use crate::{broadcast_tx, ChainError, Tx};
2022-06-08 05:48:16 -07:00
use allo_isolate::{ffi, IntoDart};
use android_logger::Config;
use lazy_static::lazy_static;
use log::Level;
use std::ffi::{CStr, CString};
use std::io::Read;
use std::os::raw::c_char;
2022-06-16 03:13:58 -07:00
use std::sync::atomic::{AtomicBool, Ordering};
2022-06-08 05:48:16 -07:00
use std::sync::Mutex;
use zcash_primitives::transaction::builder::Progress;
static mut POST_COBJ: Option<ffi::DartPostCObjectFnType> = None;
2022-06-16 03:13:58 -07:00
static IS_ERROR: AtomicBool = AtomicBool::new(false);
2022-06-08 05:48:16 -07:00
2022-06-09 04:28:37 -07:00
#[no_mangle]
pub unsafe extern "C" fn dummy_export() {}
2022-06-08 05:48:16 -07:00
#[no_mangle]
pub unsafe extern "C" fn dart_post_cobject(ptr: ffi::DartPostCObjectFnType) {
POST_COBJ = Some(ptr);
}
macro_rules! from_c_str {
($v: ident) => {
let $v = CStr::from_ptr($v).to_string_lossy();
};
}
fn to_c_str(s: String) -> *mut c_char {
CString::new(s).unwrap().into_raw()
}
fn try_init_logger() {
android_logger::init_once(
Config::default()
// .format(|buf, record| {
// writeln!(
// buf,
// "{:?}-{:?}: {}",
// record.file(),
// record.line(),
// record.args()
// )
// })
.with_min_level(Level::Info),
);
}
fn log_result<T: Default>(result: anyhow::Result<T>) -> T {
match result {
Err(err) => {
log::error!("{}", err);
T::default()
}
Ok(v) => v,
}
}
fn log_string(result: anyhow::Result<String>) -> String {
match result {
Err(err) => {
log::error!("{}", err);
2022-06-16 03:13:58 -07:00
IS_ERROR.store(true, Ordering::Release);
2022-06-08 05:48:16 -07:00
format!("{}", err)
}
2022-06-16 03:13:58 -07:00
Ok(v) => {
IS_ERROR.store(false, Ordering::Release);
v
}
2022-06-08 05:48:16 -07:00
}
}
fn encode_tx_result(res: anyhow::Result<Vec<u8>>) -> Vec<u8> {
let mut v = vec![];
match res {
Ok(raw_tx) => {
v.push(0x00);
v.extend(raw_tx);
}
Err(e) => {
v.push(0x01);
v.extend(e.to_string().as_bytes());
}
}
v
}
2022-06-16 03:13:58 -07:00
#[no_mangle]
pub unsafe extern "C" fn get_error() -> bool {
IS_ERROR.load(Ordering::Acquire)
}
2022-06-08 05:48:16 -07:00
#[no_mangle]
pub unsafe extern "C" fn init_wallet(db_path: *mut c_char) {
try_init_logger();
from_c_str!(db_path);
let _ = init_coin(0, &format!("{}/zec.db", &db_path));
let _ = init_coin(1, &format!("{}/yec.db", &db_path));
}
#[no_mangle]
pub unsafe extern "C" fn set_active(active: u8) {
crate::coinconfig::set_active(active);
}
#[no_mangle]
pub unsafe extern "C" fn set_active_account(coin: u8, id: u32) {
crate::coinconfig::set_active_account(coin, id);
}
#[no_mangle]
pub unsafe extern "C" fn set_coin_lwd_url(coin: u8, lwd_url: *mut c_char) {
from_c_str!(lwd_url);
crate::coinconfig::set_coin_lwd_url(coin, &lwd_url);
}
#[no_mangle]
pub unsafe extern "C" fn reset_app() {
let res = || {
crate::api::account::reset_db(0)?;
crate::api::account::reset_db(1)?;
Ok(())
};
log_result(res())
}
#[no_mangle]
pub unsafe extern "C" fn new_account(
coin: u8,
name: *mut c_char,
data: *mut c_char,
index: i32,
) -> u32 {
from_c_str!(name);
from_c_str!(data);
let data = if !data.is_empty() {
Some(data.to_string())
} else {
None
};
let index = if index >= 0 { Some(index as u32) } else { None };
let res = crate::api::account::new_account(coin, &name, data, index);
log_result(res)
}
#[no_mangle]
pub unsafe extern "C" fn new_sub_account(name: *mut c_char, index: i32) -> u32 {
from_c_str!(name);
let index = if index >= 0 { Some(index as u32) } else { None };
let res = crate::api::account::new_sub_account(&name, index);
log_result(res)
}
lazy_static! {
static ref SYNC_LOCK: Mutex<()> = Mutex::new(());
}
#[tokio::main]
#[no_mangle]
pub async unsafe extern "C" fn warp(coin: u8, get_tx: bool, anchor_offset: u32, port: i64) -> u8 {
let lock = SYNC_LOCK.try_lock();
if let Ok(_) = lock {
let res = async {
log::info!("Sync started");
let result = crate::api::sync::coin_sync(coin, get_tx, anchor_offset, move |height| {
let mut height = height.into_dart();
if port != 0 {
if let Some(p) = POST_COBJ {
p(port, &mut height);
}
}
})
.await;
log::info!("Sync finished");
crate::api::mempool::scan().await?;
match result {
Ok(_) => Ok(0),
Err(err) => {
if let Some(e) = err.downcast_ref::<ChainError>() {
match e {
ChainError::Reorg => Ok(1),
ChainError::Busy => Ok(2),
}
} else {
log::error!("{}", err);
Ok(0xFF)
}
}
}
};
let r = res.await;
log_result(r)
} else {
0
}
}
#[no_mangle]
pub unsafe extern "C" fn is_valid_key(coin: u8, key: *mut c_char) -> i8 {
from_c_str!(key);
crate::key2::is_valid_key(coin, &key)
}
#[no_mangle]
pub unsafe extern "C" fn valid_address(coin: u8, address: *mut c_char) -> bool {
from_c_str!(address);
crate::key2::is_valid_address(coin, &address)
}
#[no_mangle]
pub unsafe extern "C" fn new_diversified_address() -> *mut c_char {
let res = || crate::api::account::new_diversified_address();
to_c_str(log_string(res()))
}
#[tokio::main]
#[no_mangle]
pub async unsafe extern "C" fn get_latest_height() -> u32 {
let height = crate::api::sync::get_latest_height().await;
log_result(height)
}
fn report_progress(progress: Progress, port: i64) {
if port != 0 {
let progress = match progress.end() {
Some(end) => (progress.cur() * 100 / end) as i32,
None => -(progress.cur() as i32),
};
let mut progress = progress.into_dart();
unsafe {
if let Some(p) = POST_COBJ {
p(port, &mut progress);
}
}
}
}
#[tokio::main]
#[no_mangle]
pub async unsafe extern "C" fn send_multi_payment(
recipients_json: *mut c_char,
use_transparent: bool,
anchor_offset: u32,
port: i64,
) -> *mut c_char {
from_c_str!(recipients_json);
let res = async move {
let height = crate::api::sync::get_latest_height().await?;
let recipients = crate::api::payment::parse_recipients(&recipients_json)?;
let res = crate::api::payment::build_sign_send_multi_payment(
height,
&recipients,
use_transparent,
anchor_offset,
Box::new(move |progress| {
report_progress(progress, port);
}),
)
.await?;
Ok(res)
};
to_c_str(log_string(res.await))
}
#[tokio::main]
#[no_mangle]
pub async unsafe extern "C" fn skip_to_last_height(coin: u8) {
let res = crate::api::sync::skip_to_last_height(coin).await;
log_result(res)
}
#[tokio::main]
#[no_mangle]
pub async unsafe extern "C" fn rewind_to_height(height: u32) {
let res = crate::api::sync::rewind_to_height(height).await;
log_result(res)
}
#[tokio::main]
#[no_mangle]
pub async unsafe extern "C" fn mempool_sync() -> i64 {
let res = crate::api::mempool::scan().await;
log_result(res)
}
#[no_mangle]
pub unsafe extern "C" fn mempool_reset() {
let c = CoinConfig::get_active();
let mut mempool = c.mempool.lock().unwrap();
log_result(mempool.clear());
}
#[no_mangle]
pub unsafe extern "C" fn get_mempool_balance() -> i64 {
let c = CoinConfig::get_active();
let mempool = c.mempool.lock().unwrap();
mempool.get_unconfirmed_balance()
}
#[tokio::main]
#[no_mangle]
pub async unsafe extern "C" fn get_taddr_balance(coin: u8, id_account: u32) -> u64 {
let res = if coin == 0xFF {
crate::api::account::get_taddr_balance_default().await
} else {
crate::api::account::get_taddr_balance(coin, id_account).await
};
log_result(res)
}
#[tokio::main]
#[no_mangle]
pub async unsafe extern "C" fn shield_taddr() -> *mut c_char {
let res = crate::api::payment::shield_taddr().await;
to_c_str(log_string(res))
}
#[tokio::main]
#[no_mangle]
pub async unsafe extern "C" fn scan_transparent_accounts(gap_limit: u32) {
let res = crate::api::account::scan_transparent_accounts(gap_limit as usize).await;
log_result(res)
}
#[tokio::main]
#[no_mangle]
pub async unsafe extern "C" fn prepare_multi_payment(
recipients_json: *mut c_char,
use_transparent: bool,
anchor_offset: u32,
) -> *mut c_char {
from_c_str!(recipients_json);
let res = async {
let last_height = crate::api::sync::get_latest_height().await?;
let recipients = crate::api::payment::parse_recipients(&recipients_json)?;
let tx = crate::api::payment::build_only_multi_payment(
last_height,
&recipients,
use_transparent,
anchor_offset,
2022-06-16 03:13:58 -07:00
)
.await?;
2022-06-10 22:40:32 -07:00
let tx_str = serde_json::to_string(&tx)?;
Ok(tx_str)
2022-06-08 05:48:16 -07:00
};
to_c_str(log_string(res.await))
}
#[tokio::main]
#[no_mangle]
pub async unsafe extern "C" fn sign(tx_filename: *mut c_char, port: i64) -> *mut c_char {
from_c_str!(tx_filename);
let res = async {
let mut file = std::fs::File::open(&tx_filename.to_string())?;
let mut s = String::new();
file.read_to_string(&mut s)?;
2022-06-10 22:40:32 -07:00
let tx: Tx = serde_json::from_str(&s)?;
2022-06-08 05:48:16 -07:00
let raw_tx = crate::api::payment::sign_only_multi_payment(
2022-06-10 22:40:32 -07:00
&tx,
2022-06-08 05:48:16 -07:00
Box::new(move |progress| {
report_progress(progress, port);
}),
)
.await?;
Ok(raw_tx)
};
let tx_hex = hex::encode(encode_tx_result(res.await));
to_c_str(tx_hex)
}
#[tokio::main]
#[no_mangle]
pub async unsafe extern "C" fn broadcast(tx_filename: *mut c_char) -> *mut c_char {
from_c_str!(tx_filename);
let res = async {
let mut file = std::fs::File::open(&tx_filename.to_string())?;
let mut s = String::new();
file.read_to_string(&mut s)?;
let tx = hex::decode(s.trim_end())?;
broadcast_tx(&tx).await
};
to_c_str(log_string(res.await))
}
#[tokio::main]
#[no_mangle]
pub async unsafe extern "C" fn broadcast_txhex(txhex: *mut c_char) -> *mut c_char {
from_c_str!(txhex);
let res = async {
let tx = hex::decode(&txhex.to_string())?;
broadcast_tx(&tx).await
};
to_c_str(log_string(res.await))
}
#[tokio::main]
#[no_mangle]
pub async unsafe extern "C" fn get_activation_date() -> u32 {
let res = crate::api::sync::get_activation_date().await;
log_result(res)
}
#[tokio::main]
#[no_mangle]
pub async unsafe extern "C" fn get_block_by_time(time: u32) -> u32 {
let res = crate::api::sync::get_block_by_time(time).await;
log_result(res)
}
#[tokio::main]
#[no_mangle]
pub async unsafe extern "C" fn sync_historical_prices(
now: i64,
days: u32,
currency: *mut c_char,
) -> u32 {
from_c_str!(currency);
let res = crate::api::historical_prices::sync_historical_prices(now, days, &currency).await;
log_result(res)
}
#[no_mangle]
pub unsafe extern "C" fn store_contact(
id: u32,
name: *mut c_char,
address: *mut c_char,
dirty: bool,
) {
from_c_str!(name);
from_c_str!(address);
let res = crate::api::contact::store_contact(id, &name, &address, dirty);
log_result(res)
}
#[tokio::main]
#[no_mangle]
pub async unsafe extern "C" fn commit_unsaved_contacts(anchor_offset: u32) -> *mut c_char {
let res = crate::api::contact::commit_unsaved_contacts(anchor_offset).await;
to_c_str(log_string(res))
}
#[no_mangle]
pub unsafe extern "C" fn mark_message_read(message: u32, read: bool) {
let res = crate::api::message::mark_message_read(message, read);
log_result(res)
}
#[no_mangle]
pub unsafe extern "C" fn mark_all_messages_read(read: bool) {
let res = crate::api::message::mark_all_messages_read(read);
log_result(res)
}
#[no_mangle]
pub unsafe extern "C" fn truncate_data() {
let res = crate::api::account::truncate_data();
log_result(res)
}
#[no_mangle]
pub unsafe extern "C" fn delete_account(coin: u8, account: u32) {
let res = crate::api::account::delete_account(coin, account);
log_result(res)
}
#[no_mangle]
pub unsafe extern "C" fn make_payment_uri(
address: *mut c_char,
amount: u64,
memo: *mut c_char,
) -> *mut c_char {
from_c_str!(memo);
from_c_str!(address);
let res = crate::api::payment_uri::make_payment_uri(&address, amount, &memo);
to_c_str(log_string(res))
}
#[no_mangle]
pub unsafe extern "C" fn parse_payment_uri(uri: *mut c_char) -> *mut c_char {
from_c_str!(uri);
2022-06-10 11:41:05 -07:00
let payment_json = || {
let payment = crate::api::payment_uri::parse_payment_uri(&uri)?;
let payment_json = serde_json::to_string(&payment)?;
Ok(payment_json)
};
to_c_str(log_string(payment_json()))
2022-06-08 05:48:16 -07:00
}
#[no_mangle]
pub unsafe extern "C" fn generate_random_enc_key() -> *mut c_char {
to_c_str(log_string(crate::key2::generate_random_enc_key()))
}
#[no_mangle]
pub unsafe extern "C" fn get_full_backup(key: *mut c_char) -> *mut c_char {
from_c_str!(key);
let res = || {
let mut accounts = vec![];
for coin in [0, 1] {
accounts.extend(crate::api::fullbackup::get_full_backup(coin)?);
}
let backup = crate::api::fullbackup::encrypt_backup(&accounts, &key)?;
Ok(backup)
};
to_c_str(log_string(res()))
}
#[no_mangle]
pub unsafe extern "C" fn restore_full_backup(key: *mut c_char, backup: *mut c_char) -> *mut c_char {
from_c_str!(key);
from_c_str!(backup);
let res = || {
let accounts = crate::api::fullbackup::decrypt_backup(&key, &backup)?;
for coin in [0, 1] {
crate::api::fullbackup::restore_full_backup(coin, &accounts)?;
}
Ok(String::new())
};
to_c_str(log_string(res()))
}