feat(wallet-ffi): mnemonic checnges

This commit is contained in:
Pravdyvy 2026-06-09 19:47:12 +03:00
parent 4577f2cbcd
commit a3ed222887
6 changed files with 3317 additions and 35 deletions

3203
flake.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -99,6 +99,7 @@
pkgs.clang
pkgs.llvmPackages.libclang.lib
pkgs.gnutar # Required for crane's archive operations (macOS tar lacks --sort)
pkgs.python3 # Required for correct builds now, as python is sandboxed in nix builds
];
LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib";
# Point the risc0-circuit-recursion build script to the pre-fetched zip
@ -125,7 +126,7 @@
cargoExtraArgs = "-p wallet-ffi";
postInstall = ''
mkdir -p $out/include
cp wallet-ffi/wallet_ffi.h $out/include/
cp lez/wallet-ffi/wallet_ffi.h $out/include/
''
+ pkgs.lib.optionalString pkgs.stdenv.isDarwin ''
install_name_tool -id @rpath/libwallet_ffi.dylib $out/lib/libwallet_ffi.dylib

View File

@ -1,7 +1,7 @@
//! Wallet lifecycle management functions.
use std::{
ffi::{c_char, CStr},
ffi::{c_char, CStr, CString},
path::PathBuf,
ptr,
sync::Mutex,
@ -20,6 +20,22 @@ pub(crate) struct WalletWrapper {
pub core: Mutex<WalletCore>,
}
#[repr(C)]
pub struct FfiCreateWalletResult {
pub wallet: *mut WalletHandle,
/// C compatible(null terminated) string.
pub mnemonic: *mut *const c_char,
}
impl Default for FfiCreateWalletResult {
fn default() -> Self {
Self {
wallet: std::ptr::null_mut(),
mnemonic: std::ptr::null_mut(),
}
}
}
/// Helper to get the wallet wrapper from an opaque handle.
pub(crate) fn get_wallet(
handle: *mut WalletHandle,
@ -71,8 +87,8 @@ fn c_str_to_path(ptr: *const c_char, name: &str) -> Result<PathBuf, WalletFfiErr
/// - `password`: Password for encrypting the wallet seed
///
/// # Returns
/// - Opaque wallet handle on success
/// - Null pointer on error (call `wallet_ffi_get_last_error()` for details)
/// - Result, which contains opaque wallet handle and mnemonic words on success
/// - Result with null pointers on error (call `wallet_ffi_get_last_error()` for details)
///
/// # Safety
/// All string parameters must be valid null-terminated UTF-8 strings.
@ -81,29 +97,41 @@ pub unsafe extern "C" fn wallet_ffi_create_new(
config_path: *const c_char,
storage_path: *const c_char,
password: *const c_char,
) -> *mut WalletHandle {
) -> FfiCreateWalletResult {
let Ok(config_path) = c_str_to_path(config_path, "config_path") else {
return ptr::null_mut();
return FfiCreateWalletResult::default();
};
let Ok(storage_path) = c_str_to_path(storage_path, "storage_path") else {
return ptr::null_mut();
return FfiCreateWalletResult::default();
};
let Ok(password) = c_str_to_string(password, "password") else {
return ptr::null_mut();
return FfiCreateWalletResult::default();
};
match WalletCore::new_init_storage(config_path, storage_path, None, &password) {
Ok((core, _mnemonic)) => {
Ok((core, mnemonic)) => {
let wrapper = Box::new(WalletWrapper {
core: Mutex::new(core),
});
Box::into_raw(wrapper).cast::<WalletHandle>()
let handle = Box::into_raw(wrapper).cast::<WalletHandle>();
let Ok(c_mnemonic_string) = CString::new(mnemonic.to_string()) else {
return FfiCreateWalletResult::default();
};
let boxed_mnemonic_string = Box::new(c_mnemonic_string.as_ptr());
let raw_mnemonic_string_pointer = Box::into_raw(boxed_mnemonic_string);
FfiCreateWalletResult {
wallet: handle,
mnemonic: raw_mnemonic_string_pointer,
}
}
Err(e) => {
print_error(format!("Failed to create wallet: {e}"));
ptr::null_mut()
FfiCreateWalletResult::default()
}
}
}
@ -204,6 +232,58 @@ pub unsafe extern "C" fn wallet_ffi_save(handle: *mut WalletHandle) -> WalletFfi
}
}
/// Restore wallet data from mnemonic and password.
///
/// # Parameters
/// - `handle`: Valid wallet handle
/// - `mnemonic`: Valid pointer to instance of `FfiMnemonic`, provided by `wallet_ffi_create_new`
/// - `password`: Valid pointer to C string.
///
/// # Returns
/// - `Success` on successful restoration
/// - Error code on failure
///
/// # Safety
/// - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
/// - `mnemonic` must be a valid pointer to instance of `FfiMnemonic`, provided by
/// `wallet_ffi_create_new`
/// - `password` must be a valid pointer to C string.
#[no_mangle]
pub unsafe extern "C" fn wallet_ffi_restore_data(
handle: *mut WalletHandle,
mnemonic: *const c_char,
password: *const c_char,
) -> WalletFfiError {
let wrapper = match get_wallet(handle) {
Ok(w) => w,
Err(e) => return e,
};
let mut wallet = match wrapper.core.lock() {
Ok(w) => w,
Err(e) => {
print_error(format!("Failed to lock wallet: {e}"));
return WalletFfiError::InternalError;
}
};
let Ok(password) = c_str_to_string(password, "password") else {
return WalletFfiError::NullPointer;
};
let Ok(mnemonic) = c_str_to_string(mnemonic, "mnemonic") else {
return WalletFfiError::NullPointer;
};
match wallet.restore_storage(&mnemonic, &password) {
Ok(()) => WalletFfiError::Success,
Err(e) => {
print_error(format!("Failed to restore wallet data: {e}"));
WalletFfiError::StorageError
}
}
}
/// Get the sequencer address from the wallet configuration.
///
/// # Parameters

View File

@ -221,6 +221,14 @@ typedef struct FfiTransferResult {
bool success;
} FfiTransferResult;
typedef struct FfiCreateWalletResult {
struct WalletHandle *wallet;
/**
* C compatible(null terminated) string.
*/
const char **mnemonic;
} FfiCreateWalletResult;
/**
* Create a new public account.
*
@ -1010,15 +1018,15 @@ void wallet_ffi_free_transfer_result(struct FfiTransferResult *result);
* - `password`: Password for encrypting the wallet seed
*
* # Returns
* - Opaque wallet handle on success
* - Null pointer on error (call `wallet_ffi_get_last_error()` for details)
* - Result, which contains opaque wallet handle and mnemonic words on success
* - Result with null pointers on error (call `wallet_ffi_get_last_error()` for details)
*
* # Safety
* All string parameters must be valid null-terminated UTF-8 strings.
*/
struct WalletHandle *wallet_ffi_create_new(const char *config_path,
const char *storage_path,
const char *password);
struct FfiCreateWalletResult wallet_ffi_create_new(const char *config_path,
const char *storage_path,
const char *password);
/**
* Open an existing wallet from storage.
@ -1068,6 +1076,28 @@ void wallet_ffi_destroy(struct WalletHandle *handle);
*/
enum WalletFfiError wallet_ffi_save(struct WalletHandle *handle);
/**
* Restore wallet data from mnemonic and password.
*
* # Parameters
* - `handle`: Valid wallet handle
* - `mnemonic`: Valid pointer to instance of `FfiMnemonic`, provided by `wallet_ffi_create_new`
* - `password`: Valid pointer to C string.
*
* # Returns
* - `Success` on successful restoration
* - Error code on failure
*
* # Safety
* - `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`
* - `mnemonic` must be a valid pointer to instance of `FfiMnemonic`, provided by
* `wallet_ffi_create_new`
* - `password` must be a valid pointer to C string.
*/
enum WalletFfiError wallet_ffi_restore_data(struct WalletHandle *handle,
const char *mnemonic,
const char *password);
/**
* Get the sequencer address from the wallet configuration.
*

View File

@ -264,7 +264,7 @@ pub async fn execute_subcommand(
Command::RestoreKeys { depth } => {
let mnemonic = read_mnemonic_from_stdin()?;
let password = read_password_from_stdin()?;
wallet_core.restore_storage(&mnemonic, &password)?;
wallet_core.restore_storage(&mnemonic.to_string(), &password)?;
execute_keys_restoration(wallet_core, depth).await?;
SubcommandReturnValue::Empty

View File

@ -199,8 +199,8 @@ impl WalletCore {
}
/// Restore storage from an existing mnemonic phrase.
pub fn restore_storage(&mut self, mnemonic: &Mnemonic, password: &str) -> Result<()> {
self.storage.restore(mnemonic, password)
pub fn restore_storage(&mut self, mnemonic: &str, password: &str) -> Result<()> {
self.storage.restore(&Mnemonic::parse(mnemonic)?, password)
}
/// Store persistent data at home.