diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 5cb61e0..8188ce1 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -524,7 +524,8 @@ checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" [[package]] name = "equihash" version = "0.2.0" -source = "git+https://github.com/zcash/librustzcash.git?rev=6047c1d0030b2a40abd35cbc7ba15bd2bd63fc8d#6047c1d0030b2a40abd35cbc7ba15bd2bd63fc8d" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab579d7cf78477773b03e80bc2f89702ef02d7112c711d54ca93dcdce68533d5" dependencies = [ "blake2b_simd", "byteorder", @@ -533,7 +534,8 @@ dependencies = [ [[package]] name = "f4jumble" version = "0.1.0" -source = "git+https://github.com/zcash/librustzcash.git?rev=6047c1d0030b2a40abd35cbc7ba15bd2bd63fc8d#6047c1d0030b2a40abd35cbc7ba15bd2bd63fc8d" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a83e8d7fd0c526af4aad893b7c9fe41e2699ed8a776a6c74aecdeafe05afc75" dependencies = [ "blake2b_simd", ] @@ -1062,7 +1064,7 @@ dependencies = [ "serde", "subtle", "tracing", - "zcash_note_encryption 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "zcash_note_encryption", ] [[package]] @@ -1422,6 +1424,7 @@ dependencies = [ "fallible-iterator", "fallible-streaming-iterator", "hashlink", + "lazy_static", "libsqlite3-sys", "memchr", "smallvec", @@ -1452,7 +1455,8 @@ checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" [[package]] name = "schemer" version = "0.2.0" -source = "git+https://github.com/aschampion/schemer.git?rev=6726b60f43f72c6e24a18d31be0ec7d42829e5e1#6726b60f43f72c6e24a18d31be0ec7d42829e5e1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48f0ed79b582101b59740acd981e58eaa3bf8c4b1179e9a0124a7df1e08e98b3" dependencies = [ "daggy", "log", @@ -1462,8 +1466,9 @@ dependencies = [ [[package]] name = "schemer-rusqlite" -version = "0.2.0" -source = "git+https://github.com/aschampion/schemer.git?rev=6726b60f43f72c6e24a18d31be0ec7d42829e5e1#6726b60f43f72c6e24a18d31be0ec7d42829e5e1" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1f34ab2dd976536b8518fe5b868756cf6e6caec89f38d8b6f432ba27f1d5f27" dependencies = [ "rusqlite", "schemer", @@ -2050,7 +2055,8 @@ dependencies = [ [[package]] name = "zcash_address" version = "0.2.0" -source = "git+https://github.com/zcash/librustzcash.git?rev=6047c1d0030b2a40abd35cbc7ba15bd2bd63fc8d#6047c1d0030b2a40abd35cbc7ba15bd2bd63fc8d" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "804268e702b664fc09d3e2ce82786d0addf4ae57ba6976469be63e09066bf9f7" dependencies = [ "bech32", "bs58", @@ -2060,8 +2066,9 @@ dependencies = [ [[package]] name = "zcash_client_backend" -version = "0.5.0" -source = "git+https://github.com/zcash/librustzcash.git?rev=6047c1d0030b2a40abd35cbc7ba15bd2bd63fc8d#6047c1d0030b2a40abd35cbc7ba15bd2bd63fc8d" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee7748e874300bf574bdb524108b8967d3e58685aa1705dd2efbcfabb21b89d7" dependencies = [ "base64", "bech32", @@ -2085,14 +2092,15 @@ dependencies = [ "which", "zcash_address", "zcash_encoding", - "zcash_note_encryption 0.2.0 (git+https://github.com/zcash/librustzcash.git?rev=6047c1d0030b2a40abd35cbc7ba15bd2bd63fc8d)", + "zcash_note_encryption", "zcash_primitives", ] [[package]] name = "zcash_client_sqlite" -version = "0.3.0" -source = "git+https://github.com/zcash/librustzcash.git?rev=6047c1d0030b2a40abd35cbc7ba15bd2bd63fc8d#6047c1d0030b2a40abd35cbc7ba15bd2bd63fc8d" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9625b097932fc26f4b549042eafff922b57bcd421edba408abf6334a97298636" dependencies = [ "bs58", "group", @@ -2112,7 +2120,8 @@ dependencies = [ [[package]] name = "zcash_encoding" version = "0.2.0" -source = "git+https://github.com/zcash/librustzcash.git?rev=6047c1d0030b2a40abd35cbc7ba15bd2bd63fc8d#6047c1d0030b2a40abd35cbc7ba15bd2bd63fc8d" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f03391b81727875efa6ac0661a20883022b6fba92365dc121c48fa9b00c5aac0" dependencies = [ "byteorder", "nonempty", @@ -2131,22 +2140,11 @@ dependencies = [ "subtle", ] -[[package]] -name = "zcash_note_encryption" -version = "0.2.0" -source = "git+https://github.com/zcash/librustzcash.git?rev=6047c1d0030b2a40abd35cbc7ba15bd2bd63fc8d#6047c1d0030b2a40abd35cbc7ba15bd2bd63fc8d" -dependencies = [ - "chacha20", - "chacha20poly1305", - "cipher 0.4.3", - "rand_core", - "subtle", -] - [[package]] name = "zcash_primitives" -version = "0.8.1" -source = "git+https://github.com/zcash/librustzcash.git?rev=6047c1d0030b2a40abd35cbc7ba15bd2bd63fc8d#6047c1d0030b2a40abd35cbc7ba15bd2bd63fc8d" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7e33ec9068388e8de106a78268f90487d6975b171ee197aef16cc64c093486d" dependencies = [ "aes", "bip0039", @@ -2175,13 +2173,14 @@ dependencies = [ "subtle", "zcash_address", "zcash_encoding", - "zcash_note_encryption 0.2.0 (git+https://github.com/zcash/librustzcash.git?rev=6047c1d0030b2a40abd35cbc7ba15bd2bd63fc8d)", + "zcash_note_encryption", ] [[package]] name = "zcash_proofs" -version = "0.8.0" -source = "git+https://github.com/zcash/librustzcash.git?rev=6047c1d0030b2a40abd35cbc7ba15bd2bd63fc8d#6047c1d0030b2a40abd35cbc7ba15bd2bd63fc8d" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77381adc72286874e563ee36ba99953946abcbd195ada45440a2754ca823d407" dependencies = [ "bellman", "blake2b_simd", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index ad64461..95e32a7 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -19,10 +19,10 @@ secp256k1 = "0.21" secrecy = "0.8" zcash_address = { version = "0.2" } -zcash_client_backend = { version = "0.5", features = ["transparent-inputs", "unstable"] } -zcash_client_sqlite = { version = "0.3", features = ["transparent-inputs", "unstable"] } -zcash_primitives = "0.8.1" -zcash_proofs = "0.8" +zcash_client_backend = { version = "0.6", features = ["transparent-inputs", "unstable"] } +zcash_client_sqlite = { version = "0.4", features = ["transparent-inputs", "unstable"] } +zcash_primitives = "0.9" +zcash_proofs = "0.9" [build-dependencies] cbindgen = "0.14" @@ -35,18 +35,6 @@ crate-type = ["staticlib"] [profile.release] lto = true -# Revision corresponds to zcash_primitives 0.6.0 plus the NU5 mainnet activation height. -# We also need zcash_client_backend and zcash_client_sqlite, which haven't been published -# with NU5 updates yet. -[patch.crates-io] -zcash_address = { git = 'https://github.com/zcash/librustzcash.git', rev='6047c1d0030b2a40abd35cbc7ba15bd2bd63fc8d' } -zcash_client_backend = { git = 'https://github.com/zcash/librustzcash.git', rev='6047c1d0030b2a40abd35cbc7ba15bd2bd63fc8d' } -zcash_client_sqlite = { git = 'https://github.com/zcash/librustzcash.git', rev='6047c1d0030b2a40abd35cbc7ba15bd2bd63fc8d' } -zcash_primitives = { git = 'https://github.com/zcash/librustzcash.git', rev='6047c1d0030b2a40abd35cbc7ba15bd2bd63fc8d' } -zcash_proofs = { git = 'https://github.com/zcash/librustzcash.git', rev='6047c1d0030b2a40abd35cbc7ba15bd2bd63fc8d' } -schemer = { git = "https://github.com/aschampion/schemer.git", rev = "6726b60f43f72c6e24a18d31be0ec7d42829e5e1" } -schemer-rusqlite = { git = "https://github.com/aschampion/schemer.git", rev = "6726b60f43f72c6e24a18d31be0ec7d42829e5e1" } - [features] mainnet = ["zcash_client_sqlite/mainnet"] testnet = [] diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 9533169..edca8d0 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -1,3 +1,5 @@ +#![deny(unsafe_op_in_unsafe_fn)] + use failure::format_err; use ffi_helpers::panic::catch_panic; use schemer::MigratorError; @@ -20,21 +22,22 @@ use zcash_address::{ use zcash_client_backend::{ address::{RecipientAddress, UnifiedAddress}, data_api::{ - chain::{scan_cached_blocks, validate_chain}, - error::Error, + chain::{self, scan_cached_blocks, validate_chain}, wallet::{ - create_spend_to_address, decrypt_and_store_transaction, shield_transparent_funds, + decrypt_and_store_transaction, input_selection::GreedyInputSelector, + shield_transparent_funds, spend, }, WalletRead, WalletWrite, }, encoding::{decode_extended_full_viewing_key, decode_extended_spending_key, AddressCodec}, + fees::{fixed, zip317, DustOutputPolicy}, keys::{DecodingError, Era, UnifiedFullViewingKey, UnifiedSpendingKey}, wallet::{OvkPolicy, WalletTransparentOutput}, + zip321::{Payment, TransactionRequest}, }; #[allow(deprecated)] use zcash_client_sqlite::wallet::get_rewind_height; use zcash_client_sqlite::{ - error::SqliteClientError, wallet::init::{init_accounts_table, init_blocks_table, init_wallet_db, WalletMigrationError}, BlockDb, NoteId, WalletDb, }; @@ -46,6 +49,8 @@ use zcash_primitives::{ memo::{Memo, MemoBytes}, transaction::{ components::{Amount, OutPoint, TxOut}, + fees::fixed::FeeRule as FixedFeeRule, + fees::zip317::FeeRule as Zip317FeeRule, Transaction, }, zip32::AccountId, @@ -86,10 +91,9 @@ unsafe fn wallet_db( db_data_len: usize, network: Network, ) -> Result, failure::Error> { - let db_data = Path::new(OsStr::from_bytes(slice::from_raw_parts( - db_data, - db_data_len, - ))); + let db_data = Path::new(OsStr::from_bytes(unsafe { + slice::from_raw_parts(db_data, db_data_len) + })); WalletDb::for_path(db_data, network) .map_err(|e| format_err!("Error opening wallet database connection: {}", e)) } @@ -105,10 +109,9 @@ unsafe fn wallet_db( /// - The total size `db_data_len` must be no larger than `isize::MAX`. See the safety /// documentation of pointer::offset. unsafe fn block_db(cache_db: *const u8, cache_db_len: usize) -> Result { - let cache_db = Path::new(OsStr::from_bytes(slice::from_raw_parts( - cache_db, - cache_db_len, - ))); + let cache_db = Path::new(OsStr::from_bytes(unsafe { + slice::from_raw_parts(cache_db, cache_db_len) + })); BlockDb::for_path(cache_db) .map_err(|e| format_err!("Error opening block source database connection: {}", e)) } @@ -130,7 +133,7 @@ pub extern "C" fn zcashlc_last_error_length() -> i32 { /// pointer::offset. #[no_mangle] pub unsafe extern "C" fn zcashlc_error_message_utf8(buf: *mut c_char, length: i32) -> i32 { - ffi_helpers::error_handling::error_message_utf8(buf, length) + unsafe { ffi_helpers::error_handling::error_message_utf8(buf, length) } } /// Clears the record of the last error message. @@ -160,7 +163,7 @@ pub extern "C" fn zcashlc_clear_last_error() { /// - The total size `seed_len` must be no larger than `isize::MAX`. See the safety documentation /// of pointer::offset. #[no_mangle] -pub extern "C" fn zcashlc_init_data_database( +pub unsafe extern "C" fn zcashlc_init_data_database( db_data: *const u8, db_data_len: usize, seed: *const u8, @@ -221,9 +224,10 @@ impl FFIBinaryKey { #[no_mangle] pub unsafe extern "C" fn zcashlc_free_binary_key(ptr: *mut FFIBinaryKey) { if !ptr.is_null() { - let key: Box = Box::from_raw(ptr); - let key_slice: &mut [u8] = slice::from_raw_parts_mut(key.encoding, key.encoding_len); - drop(Box::from_raw(key_slice)); + let key: Box = unsafe { Box::from_raw(ptr) }; + let key_slice: &mut [u8] = + unsafe { slice::from_raw_parts_mut(key.encoding, key.encoding_len) }; + drop(unsafe { Box::from_raw(key_slice) }); } } @@ -260,7 +264,7 @@ pub unsafe extern "C" fn zcashlc_free_binary_key(ptr: *mut FFIBinaryKey) { /// /// [ZIP 316]: https://zips.z.cash/zip-0316 #[no_mangle] -pub extern "C" fn zcashlc_create_account( +pub unsafe extern "C" fn zcashlc_create_account( db_data: *const u8, db_data_len: usize, seed: *const u8, @@ -341,11 +345,11 @@ impl FFIEncodedKeys { #[no_mangle] pub unsafe extern "C" fn zcashlc_free_keys(ptr: *mut FFIEncodedKeys) { if !ptr.is_null() { - let s: Box = Box::from_raw(ptr); + let s: Box = unsafe { Box::from_raw(ptr) }; - let slice: &mut [FFIEncodedKey] = slice::from_raw_parts_mut(s.ptr, s.len); + let slice: &mut [FFIEncodedKey] = unsafe { slice::from_raw_parts_mut(s.ptr, s.len) }; for k in slice.into_iter() { - zcashlc_string_free(k.encoding) + unsafe { zcashlc_string_free(k.encoding) } } drop(s); } @@ -369,7 +373,7 @@ pub unsafe extern "C" fn zcashlc_free_keys(ptr: *mut FFIEncodedKeys) { /// - The total size `ufvks_len` must be no larger than `isize::MAX`. See the safety /// documentation of pointer::offset. #[no_mangle] -pub extern "C" fn zcashlc_init_accounts_table_with_keys( +pub unsafe extern "C" fn zcashlc_init_accounts_table_with_keys( db_data: *const u8, db_data_len: usize, ufvks_ptr: *mut FFIEncodedKey, @@ -423,7 +427,7 @@ pub unsafe extern "C" fn zcashlc_derive_spending_key( ) -> *mut FFIBinaryKey { let res = catch_panic(|| { let network = parse_network(network_id)?; - let seed = slice::from_raw_parts(seed, seed_len); + let seed = unsafe { slice::from_raw_parts(seed, seed_len) }; let account = if account >= 0 { account as u32 } else { @@ -487,7 +491,7 @@ unsafe fn decode_usk( /// - Call [`zcashlc_string_free`] to free the memory associated with the returned pointer /// when you are done using it. #[no_mangle] -pub extern "C" fn zcashlc_spending_key_to_full_viewing_key( +pub unsafe extern "C" fn zcashlc_spending_key_to_full_viewing_key( usk_ptr: *const u8, usk_len: usize, network_id: u32, @@ -524,7 +528,7 @@ pub extern "C" fn zcashlc_spending_key_to_full_viewing_key( /// - The memory referenced by `sapling_tree_hex` must not be mutated for the duration of the /// function call. #[no_mangle] -pub extern "C" fn zcashlc_init_blocks_table( +pub unsafe extern "C" fn zcashlc_init_blocks_table( db_data: *const u8, db_data_len: usize, height: i32, @@ -571,7 +575,7 @@ pub extern "C" fn zcashlc_init_blocks_table( /// - Call [`zcashlc_string_free`] to free the memory associated with the returned pointer /// when done using it. #[no_mangle] -pub extern "C" fn zcashlc_get_current_address( +pub unsafe extern "C" fn zcashlc_get_current_address( db_data: *const u8, db_data_len: usize, account: i32, @@ -617,7 +621,7 @@ pub extern "C" fn zcashlc_get_current_address( /// - Call [`zcashlc_string_free`] to free the memory associated with the returned pointer /// when done using it. #[no_mangle] -pub extern "C" fn zcashlc_get_next_available_address( +pub unsafe extern "C" fn zcashlc_get_next_available_address( db_data: *const u8, db_data_len: usize, account: i32, @@ -664,7 +668,7 @@ pub extern "C" fn zcashlc_get_next_available_address( /// - Call [`zcashlc_free_keys`] to free the memory associated with the returned pointer /// when done using it. #[no_mangle] -pub extern "C" fn zcashlc_list_transparent_receivers( +pub unsafe extern "C" fn zcashlc_list_transparent_receivers( db_data: *const u8, db_data_len: usize, account_id: i32, @@ -718,7 +722,7 @@ pub extern "C" fn zcashlc_list_transparent_receivers( /// - Call [`zcashlc_free_typecodes`] to free the memory associated with the returned /// pointer when done using it. #[no_mangle] -pub extern "C" fn zcashlc_get_typecodes_for_unified_address_receivers( +pub unsafe extern "C" fn zcashlc_get_typecodes_for_unified_address_receivers( ua: *const c_char, len_ret: *mut usize, ) -> *mut u32 { @@ -759,7 +763,7 @@ pub extern "C" fn zcashlc_get_typecodes_for_unified_address_receivers( #[no_mangle] pub unsafe extern "C" fn zcashlc_free_typecodes(data: *mut u32, len: usize) { if !data.is_null() { - let s = Box::from_raw(slice::from_raw_parts_mut(data, len)); + let s = unsafe { Box::from_raw(slice::from_raw_parts_mut(data, len)) }; drop(s); } } @@ -786,7 +790,7 @@ impl zcash_address::TryFromRawAddress for UnifiedAddressParser { /// - Call [`zcashlc_string_free`] to free the memory associated with the returned pointer /// when done using it. #[no_mangle] -pub extern "C" fn zcashlc_get_transparent_receiver_for_unified_address( +pub unsafe extern "C" fn zcashlc_get_transparent_receiver_for_unified_address( ua: *const c_char, ) -> *mut c_char { let res = catch_panic(|| { @@ -827,7 +831,7 @@ pub extern "C" fn zcashlc_get_transparent_receiver_for_unified_address( /// - Call [`zcashlc_string_free`] to free the memory associated with the returned pointer /// when done using it. #[no_mangle] -pub extern "C" fn zcashlc_get_sapling_receiver_for_unified_address( +pub unsafe extern "C" fn zcashlc_get_sapling_receiver_for_unified_address( ua: *const c_char, ) -> *mut c_char { let res = catch_panic(|| { @@ -862,7 +866,7 @@ pub extern "C" fn zcashlc_get_sapling_receiver_for_unified_address( /// - `address` must be non-null and must point to a null-terminated UTF-8 string. /// - The memory referenced by `address` must not be mutated for the duration of the function call. #[no_mangle] -pub extern "C" fn zcashlc_is_valid_shielded_address( +pub unsafe extern "C" fn zcashlc_is_valid_shielded_address( address: *const c_char, network_id: u32, ) -> bool { @@ -969,7 +973,7 @@ impl TryFromAddress for AddressMetadata { /// - `address` must be non-null and must point to a null-terminated UTF-8 string. /// - The memory referenced by `address` must not be mutated for the duration of the function call. #[no_mangle] -pub extern "C" fn zcashlc_get_address_metadata( +pub unsafe extern "C" fn zcashlc_get_address_metadata( address: *const c_char, network_id_ret: *mut u32, addr_kind_ret: *mut u32, @@ -1014,7 +1018,7 @@ pub extern "C" fn zcashlc_get_address_metadata( /// - `address` must be non-null and must point to a null-terminated UTF-8 string. /// - The memory referenced by `address` must not be mutated for the duration of the function call. #[no_mangle] -pub extern "C" fn zcashlc_is_valid_transparent_address( +pub unsafe extern "C" fn zcashlc_is_valid_transparent_address( address: *const c_char, network_id: u32, ) -> bool { @@ -1044,7 +1048,7 @@ fn is_valid_transparent_address(address: &str, network: &Network) -> bool { /// - `extsk` must be non-null and must point to a null-terminated UTF-8 string. /// - The memory referenced by `extsk` must not be mutated for the duration of the function call. #[no_mangle] -pub extern "C" fn zcashlc_is_valid_sapling_extended_spending_key( +pub unsafe extern "C" fn zcashlc_is_valid_sapling_extended_spending_key( extsk: *const c_char, network_id: u32, ) -> bool { @@ -1068,7 +1072,7 @@ pub extern "C" fn zcashlc_is_valid_sapling_extended_spending_key( /// - `key` must be non-null and must point to a null-terminated UTF-8 string. /// - The memory referenced by `key` must not be mutated for the duration of the function call. #[no_mangle] -pub extern "C" fn zcashlc_is_valid_viewing_key(key: *const c_char, network_id: u32) -> bool { +pub unsafe extern "C" fn zcashlc_is_valid_viewing_key(key: *const c_char, network_id: u32) -> bool { let res = catch_panic(|| { let network = parse_network(network_id)?; @@ -1092,7 +1096,7 @@ pub extern "C" fn zcashlc_is_valid_viewing_key(key: *const c_char, network_id: u /// - The memory referenced by `ufvk` must not be mutated for the duration of the /// function call. #[no_mangle] -pub extern "C" fn zcashlc_is_valid_unified_full_viewing_key( +pub unsafe extern "C" fn zcashlc_is_valid_unified_full_viewing_key( ufvk: *const c_char, network_id: u32, ) -> bool { @@ -1114,7 +1118,7 @@ pub extern "C" fn zcashlc_is_valid_unified_full_viewing_key( /// - The memory referenced by `address` must not be mutated for the duration of the /// function call. #[no_mangle] -pub extern "C" fn zcashlc_is_valid_unified_address( +pub unsafe extern "C" fn zcashlc_is_valid_unified_address( address: *const c_char, network_id: u32, ) -> bool { @@ -1147,7 +1151,7 @@ fn is_valid_unified_address(address: &str, network: &Network) -> bool { /// - The total size `db_data_len` must be no larger than `isize::MAX`. See the safety /// documentation of pointer::offset. #[no_mangle] -pub extern "C" fn zcashlc_get_balance( +pub unsafe extern "C" fn zcashlc_get_balance( db_data: *const u8, db_data_len: usize, account: i32, @@ -1190,7 +1194,7 @@ pub extern "C" fn zcashlc_get_balance( /// - The total size `db_data_len` must be no larger than `isize::MAX`. See the safety /// documentation of pointer::offset. #[no_mangle] -pub extern "C" fn zcashlc_get_verified_balance( +pub unsafe extern "C" fn zcashlc_get_verified_balance( db_data: *const u8, db_data_len: usize, account: i32, @@ -1236,7 +1240,7 @@ pub extern "C" fn zcashlc_get_verified_balance( /// - `address` must be non-null and must point to a null-terminated UTF-8 string. /// - The memory referenced by `address` must not be mutated for the duration of the function call. #[no_mangle] -pub extern "C" fn zcashlc_get_verified_transparent_balance( +pub unsafe extern "C" fn zcashlc_get_verified_transparent_balance( db_data: *const u8, db_data_len: usize, address: *const c_char, @@ -1258,7 +1262,7 @@ pub extern "C" fn zcashlc_get_verified_transparent_balance( }) .and_then(|anchor| { (&db_data) - .get_unspent_transparent_outputs(&taddr, anchor) + .get_unspent_transparent_outputs(&taddr, anchor, &[]) .map_err(|e| { format_err!("Error while fetching verified transparent balance: {}", e) }) @@ -1287,7 +1291,7 @@ pub extern "C" fn zcashlc_get_verified_transparent_balance( /// - `address` must be non-null and must point to a null-terminated UTF-8 string. /// - The memory referenced by `address` must not be mutated for the duration of the function call. #[no_mangle] -pub extern "C" fn zcashlc_get_verified_transparent_balance_for_account( +pub unsafe extern "C" fn zcashlc_get_verified_transparent_balance_for_account( db_data: *const u8, db_data_len: usize, network_id: u32, @@ -1325,7 +1329,7 @@ pub extern "C" fn zcashlc_get_verified_transparent_balance_for_account( .iter() .map(|(taddr, _)| { db_data - .get_unspent_transparent_outputs(&taddr, anchor) + .get_unspent_transparent_outputs(&taddr, anchor, &[]) .map_err(|e| { format_err!( "Error while fetching verified transparent balance: {}", @@ -1360,7 +1364,7 @@ pub extern "C" fn zcashlc_get_verified_transparent_balance_for_account( /// - `address` must be non-null and must point to a null-terminated UTF-8 string. /// - The memory referenced by `address` must not be mutated for the duration of the function call. #[no_mangle] -pub extern "C" fn zcashlc_get_total_transparent_balance( +pub unsafe extern "C" fn zcashlc_get_total_transparent_balance( db_data: *const u8, db_data_len: usize, address: *const c_char, @@ -1381,7 +1385,7 @@ pub extern "C" fn zcashlc_get_total_transparent_balance( }) .and_then(|anchor| { (&db_data) - .get_unspent_transparent_outputs(&taddr, anchor) + .get_unspent_transparent_outputs(&taddr, anchor, &[]) .map_err(|e| { format_err!("Error while fetching total transparent balance: {}", e) }) @@ -1409,7 +1413,7 @@ pub extern "C" fn zcashlc_get_total_transparent_balance( /// - `address` must be non-null and must point to a null-terminated UTF-8 string. /// - The memory referenced by `address` must not be mutated for the duration of the function call. #[no_mangle] -pub extern "C" fn zcashlc_get_total_transparent_balance_for_account( +pub unsafe extern "C" fn zcashlc_get_total_transparent_balance_for_account( db_data: *const u8, db_data_len: usize, network_id: u32, @@ -1468,7 +1472,7 @@ pub extern "C" fn zcashlc_get_total_transparent_balance_for_account( /// - Call [`zcashlc_string_free`] to free the memory associated with the returned pointer /// when done using it. #[no_mangle] -pub extern "C" fn zcashlc_get_received_memo_as_utf8( +pub unsafe extern "C" fn zcashlc_get_received_memo_as_utf8( db_data: *const u8, db_data_len: usize, id_note: i64, @@ -1508,20 +1512,22 @@ pub extern "C" fn zcashlc_get_received_memo_as_utf8( /// documentation of pointer::offset. /// - `memo_bytes_ret` must be non-null and must point to an allocated 512-byte region of memory. #[no_mangle] -pub extern "C" fn zcashlc_get_received_memo( +pub unsafe extern "C" fn zcashlc_get_received_memo( db_data: *const u8, db_data_len: usize, id_note: i64, memo_bytes_ret: *mut u8, network_id: u32, ) -> bool { - zcashlc_get_memo( - db_data, - db_data_len, - NoteId::ReceivedNoteId(id_note), - memo_bytes_ret, - network_id, - ) + unsafe { + zcashlc_get_memo( + db_data, + db_data_len, + NoteId::ReceivedNoteId(id_note), + memo_bytes_ret, + network_id, + ) + } } /// Returns the memo for a note by copying the corresponding bytes to the received @@ -1536,7 +1542,7 @@ pub extern "C" fn zcashlc_get_received_memo( /// - The total size `db_data_len` must be no larger than `isize::MAX`. See the safety /// documentation of pointer::offset. /// - `memo_bytes_ret` must be non-null and must point to an allocated 512-byte region of memory. -fn zcashlc_get_memo( +unsafe fn zcashlc_get_memo( db_data: *const u8, db_data_len: usize, note_id: NoteId, @@ -1574,7 +1580,7 @@ fn zcashlc_get_memo( /// - Call [`zcashlc_string_free`] to free the memory associated with the returned pointer /// when done using it. #[no_mangle] -pub extern "C" fn zcashlc_get_sent_memo_as_utf8( +pub unsafe extern "C" fn zcashlc_get_sent_memo_as_utf8( db_data: *const u8, db_data_len: usize, id_note: i64, @@ -1614,20 +1620,22 @@ pub extern "C" fn zcashlc_get_sent_memo_as_utf8( /// documentation of pointer::offset. /// - `memo_bytes_ret` must be non-null and must point to an allocated 512-byte region of memory. #[no_mangle] -pub extern "C" fn zcashlc_get_sent_memo( +pub unsafe extern "C" fn zcashlc_get_sent_memo( db_data: *const u8, db_data_len: usize, id_note: i64, memo_bytes_ret: *mut u8, network_id: u32, ) -> bool { - zcashlc_get_memo( - db_data, - db_data_len, - NoteId::SentNoteId(id_note), - memo_bytes_ret, - network_id, - ) + unsafe { + zcashlc_get_memo( + db_data, + db_data_len, + NoteId::SentNoteId(id_note), + memo_bytes_ret, + network_id, + ) + } } /// Checks that the scanned blocks in the data database, when combined with the recent @@ -1662,7 +1670,7 @@ pub extern "C" fn zcashlc_get_sent_memo( /// - The total size `db_data_len` must be no larger than `isize::MAX`. See the safety /// documentation of pointer::offset. #[no_mangle] -pub extern "C" fn zcashlc_validate_combined_chain( +pub unsafe extern "C" fn zcashlc_validate_combined_chain( db_cache: *const u8, db_cache_len: usize, db_data: *const u8, @@ -1682,9 +1690,9 @@ pub extern "C" fn zcashlc_validate_combined_chain( if let Err(e) = val_res { match e { - SqliteClientError::BackendError(Error::InvalidChain(upper_bound, _)) => { - let upper_bound_u32 = u32::from(upper_bound); - Ok(upper_bound_u32 as i32) + chain::error::Error::Chain(chain_error) => { + let height_u32 = u32::from(chain_error.at_height()); + Ok(height_u32 as i32) } _ => Err(format_err!("Error while validating chain: {}", e)), } @@ -1708,7 +1716,7 @@ pub extern "C" fn zcashlc_validate_combined_chain( /// - The total size `db_data_len` must be no larger than `isize::MAX`. See the safety /// documentation of pointer::offset. #[no_mangle] -pub extern "C" fn zcashlc_get_nearest_rewind_height( +pub unsafe extern "C" fn zcashlc_get_nearest_rewind_height( db_data: *const u8, db_data_len: usize, height: i32, @@ -1760,7 +1768,7 @@ pub extern "C" fn zcashlc_get_nearest_rewind_height( /// - The total size `db_data_len` must be no larger than `isize::MAX`. See the safety /// documentation of pointer::offset. #[no_mangle] -pub extern "C" fn zcashlc_rewind_to_height( +pub unsafe extern "C" fn zcashlc_rewind_to_height( db_data: *const u8, db_data_len: usize, height: i32, @@ -1810,7 +1818,7 @@ pub extern "C" fn zcashlc_rewind_to_height( /// - The total size `db_data_len` must be no larger than `isize::MAX`. See the safety /// documentation of pointer::offset. #[no_mangle] -pub extern "C" fn zcashlc_scan_blocks( +pub unsafe extern "C" fn zcashlc_scan_blocks( db_cache: *const u8, db_cache_len: usize, db_data: *const u8, @@ -1857,7 +1865,7 @@ pub extern "C" fn zcashlc_scan_blocks( /// - The total size `script_bytes_len` must be no larger than `isize::MAX`. See the safety /// documentation of pointer::offset. #[no_mangle] -pub extern "C" fn zcashlc_put_utxo( +pub unsafe extern "C" fn zcashlc_put_utxo( db_data: *const u8, db_data_len: usize, txid_bytes: *const u8, @@ -1919,7 +1927,7 @@ pub extern "C" fn zcashlc_put_utxo( /// - The total size `tx_len` must be no larger than `isize::MAX`. See the safety /// documentation of pointer::offset. #[no_mangle] -pub extern "C" fn zcashlc_decrypt_and_store_transaction( +pub unsafe extern "C" fn zcashlc_decrypt_and_store_transaction( db_data: *const u8, db_data_len: usize, tx: *const u8, @@ -1986,7 +1994,7 @@ pub extern "C" fn zcashlc_decrypt_and_store_transaction( /// - The total size `output_params_len` must be no larger than `isize::MAX`. See the safety /// documentation of pointer::offset. #[no_mangle] -pub extern "C" fn zcashlc_create_to_address( +pub unsafe extern "C" fn zcashlc_create_to_address( db_data: *const u8, db_data_len: usize, usk_ptr: *const u8, @@ -2000,6 +2008,7 @@ pub extern "C" fn zcashlc_create_to_address( output_params_len: usize, network_id: u32, min_confirmations: u32, + use_zip317_fees: bool, ) -> i64 { let res = catch_panic(|| { let network = parse_network(network_id)?; @@ -2046,18 +2055,51 @@ pub extern "C" fn zcashlc_create_to_address( let prover = LocalTxProver::new(spend_params, output_params); - create_spend_to_address( - &mut db_data, - &network, - prover, - &usk, - &to, - value, - memo, - OvkPolicy::Sender, - min_confirmations, - ) - .map_err(|e| format_err!("Error while sending funds: {}", e)) + let req = TransactionRequest::new(vec![Payment { + recipient_address: to, + amount: value, + memo: memo, + label: None, + message: None, + other_params: vec![], + }]) + .map_err(|e| format_err!("Error creating transaction request: {:?}", e))?; + + if use_zip317_fees { + let input_selector = GreedyInputSelector::new( + zip317::SingleOutputChangeStrategy::new(Zip317FeeRule::standard()), + DustOutputPolicy::default(), + ); + + spend( + &mut db_data, + &network, + prover, + &input_selector, + &usk, + req, + OvkPolicy::Sender, + min_confirmations, + ) + .map_err(|e| format_err!("Error while sending funds: {}", e)) + } else { + let input_selector = GreedyInputSelector::new( + fixed::SingleOutputChangeStrategy::new(FixedFeeRule::standard()), + DustOutputPolicy::default(), + ); + + spend( + &mut db_data, + &network, + prover, + &input_selector, + &usk, + req, + OvkPolicy::Sender, + min_confirmations, + ) + .map_err(|e| format_err!("Error while sending funds: {}", e)) + } }); unwrap_exc_or(res, -1) } @@ -2082,7 +2124,7 @@ pub extern "C" fn zcashlc_branch_id_for_height(height: i32, network_id: u32) -> #[allow(clippy::not_unsafe_ptr_arg_deref)] pub unsafe extern "C" fn zcashlc_string_free(s: *mut c_char) { if !s.is_null() { - let s = CString::from_raw(s); + let s = unsafe { CString::from_raw(s) }; drop(s); } } @@ -2115,7 +2157,7 @@ pub unsafe extern "C" fn zcashlc_string_free(s: *mut c_char) { /// - The total size `output_params_len` must be no larger than `isize::MAX`. See the safety /// documentation of pointer::offset. #[no_mangle] -pub extern "C" fn zcashlc_shield_funds( +pub unsafe extern "C" fn zcashlc_shield_funds( db_data: *const u8, db_data_len: usize, usk_ptr: *const u8, @@ -2126,6 +2168,7 @@ pub extern "C" fn zcashlc_shield_funds( output_params: *const u8, output_params_len: usize, network_id: u32, + use_zip317_fees: bool, ) -> i64 { let res = catch_panic(|| { let network = parse_network(network_id)?; @@ -2177,16 +2220,41 @@ pub extern "C" fn zcashlc_shield_funds( .cloned() .collect(); - shield_transparent_funds( - &mut update_ops, - &network, - LocalTxProver::new(spend_params, output_params), - &usk, - &taddrs, - &memo_bytes, - ANCHOR_OFFSET, - ) - .map_err(|e| format_err!("Error while shielding transaction: {}", e)) + if use_zip317_fees { + let input_selector = GreedyInputSelector::new( + zip317::SingleOutputChangeStrategy::new(Zip317FeeRule::standard()), + DustOutputPolicy::default(), + ); + + shield_transparent_funds( + &mut update_ops, + &network, + LocalTxProver::new(spend_params, output_params), + &input_selector, + &usk, + &taddrs, + &memo_bytes, + ANCHOR_OFFSET, + ) + .map_err(|e| format_err!("Error while shielding transaction: {}", e)) + } else { + let input_selector = GreedyInputSelector::new( + fixed::SingleOutputChangeStrategy::new(FixedFeeRule::standard()), + DustOutputPolicy::default(), + ); + + shield_transparent_funds( + &mut update_ops, + &network, + LocalTxProver::new(spend_params, output_params), + &input_selector, + &usk, + &taddrs, + &memo_bytes, + ANCHOR_OFFSET, + ) + .map_err(|e| format_err!("Error while shielding transaction: {}", e)) + } }); unwrap_exc_or(res, -1) }