Skip to content

Rust develop#103

Open
MrCyjaneK wants to merge 65 commits intodevelopfrom
rust-develop
Open

Rust develop#103
MrCyjaneK wants to merge 65 commits intodevelopfrom
rust-develop

Conversation

@MrCyjaneK
Copy link
Copy Markdown
Owner

No description provided.

sneurlax and others added 30 commits October 9, 2024 19:07
courtesy of cypherstack/flutter_libmonero and MrCyjaneK & julian-CStack's work there

remove wownero

update docs and script

add gitignore
and document the required placement
just to match the style in impls

and sneurlax/monero_c -> MrCyjaneK/monero_c
and resolve 2 clippy issues

need to test on other platforms gestured-towards here in lib.rs
see #67 (comment)

Co-authored-by: cyan <cyjan@mrcyjanek.net>
see #67 (comment)

I'm tired >.>
and update docs
@MrCyjaneK MrCyjaneK mentioned this pull request Jan 5, 2025
35 tasks
@MrCyjaneK
Copy link
Copy Markdown
Owner Author

note: checksums do not update in the bindings file

fix build
@github-actions
Copy link
Copy Markdown

github-actions bot commented Jan 5, 2025

@binarybaron
Copy link
Copy Markdown
Collaborator

I'm attempting a POC integration of this Rust wrapper here: eigenwallet/core#244. To get things running I have simply copied the wrapper into our workspace. I'll try to find a better way as we make progress with our integration. I'll also try to push changes I make to this branch as well.

@MrCyjaneK
Copy link
Copy Markdown
Owner Author

Great, there are some things i want to fix (don't log to file, allow to load the library from any directory and use proper name for it).

@binarybaron
Copy link
Copy Markdown
Collaborator

use monero_c_rust::{NetworkType, WalletConfig, WalletError, WalletManager};
use tempfile::TempDir;

fn main() -> Result<(), WalletError> {
    let manager = WalletManager::new()?;

    let temp_dir = TempDir::new().expect("Failed to create temporary directory");
    let wallet_path = temp_dir.path().join("test_wallet");
    let wallet_str = wallet_path.to_str().unwrap();

    let wallet = manager.restore_polyseed(
        wallet_str.to_string(),
        "password".to_string(),
        "capital chief route liar question fix clutch water outside pave hamster occur always learn license knife".to_string(),
        NetworkType::Stagenet,
        0, // Restore from the beginning of the blockchain.
        1, // Default KDF rounds.
        "".to_string(), // No seed offset.
        true, // Create a new wallet.
    )?;

    println!("Wallet created successfully.");

    // Print the primary address.
    println!("Primary address: {}", wallet.get_address(0, 0)?);

    // Initialize the wallet.
    let config = WalletConfig {
        daemon_address: "http://localhost:38081".to_string(),
        upper_transaction_size_limit: 10000, // TODO: use sane value.
        daemon_username: "".to_string(),
        daemon_password: "".to_string(),
        use_ssl: false,
        light_wallet: false,
        proxy_address: "".to_string(),
    };

    // Set WalletManager's daemon address
    manager.set_daemon_address(&config.daemon_address);

    // Perform the initialization.
    wallet.init(config)?;
    wallet.throw_if_error()?;

    let target_block = manager.get_height_target()?;
    println!("Target block: {}", target_block);

    // Refresh the wallet.
    wallet.refresh()?; // This calls MONERO_Wallet_startRefresh
    wallet.throw_if_error()?;

    // Wait for the refresh to complete.
    loop {
        let height = wallet
            .get_current_sync_height() // This calls MONERO_Wallet_blockChainHeight
            .expect("Failed to get blockchain height");

        let daemon_height = wallet
            .get_daemon_height() // This calls MONERO_Wallet_daemonBlockChainHeight
            .expect("Failed to get daemon height");

        println!("Current blockchain height: {} / {}", height, daemon_height);
        if height >= daemon_height {
            // After this height we can get_balance.
            break ();
        }
        // Wait one second.
        std::thread::sleep(std::time::Duration::from_secs(1));
    }

    // Get the balance.
    let balance_result = wallet.get_balance(0); // Account index 0.
    let balance = balance_result.unwrap();
    println!("Balance: {:?}", balance);

    // Clean up the wallet.
    std::fs::remove_file(wallet_str).expect("Failed to delete test wallet");
    std::fs::remove_file(format!("{}.keys", wallet_str))
        .expect("Failed to delete test wallet keys");

    Ok(())
}
2025-01-07 11:54:36,507 D Device 0 Created
2025-01-07 11:54:36,508 T refreshThreadFunc: starting refresh thread
2025-01-07 11:54:36,508 T refreshThreadFunc: waiting for refresh...
2025-01-07 11:54:36,548 I caching ringdb key
2025-01-07 11:54:36,562 D Calculated blockchain height: 1766275
2025-01-07 11:54:36,563 D Reconnecting...
2025-01-07 11:54:36,564 D Some problems at connect, message: resolve: Host not found (authoritative) [asio.netdb:1 at /Users/****/Development/monero_c/contrib/depends/aarch64-apple-darwin/include/boost/asio/detail/resolver_service.hpp:84:33 in function 'resolve']
2025-01-07 11:54:36,564 D Failed to connect to :
2025-01-07 11:54:36,564 I Failed to invoke http request to  /json_rpc
2025-01-07 11:54:36,564 E Failed to connect to daemon
2025-01-07 11:54:36,564 D Reconnecting...
2025-01-07 11:54:36,564 D Some problems at connect, message: resolve: Host not found (authoritative) [asio.netdb:1 at /Users/****/Development/monero_c/contrib/depends/aarch64-apple-darwin/include/boost/asio/detail/resolver_service.hpp:84:33 in function 'resolve']
2025-01-07 11:54:36,564 D Failed to connect to :
2025-01-07 11:54:36,564 I Failed to invoke http request to  /json_rpc
2025-01-07 11:54:36,564 E Failed to connect to daemon
2025-01-07 11:54:36,590 D /var/folders/q3/96gvm8255230tvzw3szbj0yr0000gn/T/.tmp0hltdN/test_wallet.keys is already unlocked.
Wallet created successfully.
Primary address: 56HeZM3u6xYCV8oVVh7CuWWHs7yeB1oxhNPrsEM5FKSqadTXmobLqsNEtRnyGsbN1rbDuBtWdtxtXhTJda1Lm9vcH73iSWn
2025-01-07 11:54:36,731 I [PARSE URI] regex not matched for uri: ^(([^:]*?)://)?(\[(.*)\](:(\d+))?)(.*)?
2025-01-07 11:54:36,731 I Generating SSL certificate
...
Current blockchain height: 1 / 1769997
Current blockchain height: 1769997 / 1769997

I still haven't gotten the syncing to work. Not sure why. It's also syncing way too fast. Either the restore height is not being set correctly or we are not actually syncing but only polling blocks?

@binarybaron
Copy link
Copy Markdown
Collaborator

use monero_c_rust::{NetworkType, WalletConfig, WalletError, WalletManager};
use tempfile::TempDir;

fn main() -> Result<(), WalletError> {
    let manager = WalletManager::new()?;

    let temp_dir = TempDir::new().expect("Failed to create temporary directory");
    let wallet_path = temp_dir.path().join("test_wallet");
    let wallet_str = wallet_path.to_str().unwrap();

    let wallet = manager.restore_polyseed(
        wallet_str.to_string(),
        "password".to_string(),
        "capital chief route liar question fix clutch water outside pave hamster occur always learn license knife".to_string(),
        NetworkType::Stagenet,
        0, // Restore from the beginning of the blockchain.
        1, // Default KDF rounds.
        "".to_string(), // No seed offset.
        true, // Create a new wallet.
    )?;

    println!("Wallet created successfully.");

    // Print the primary address.
    println!("Primary address: {}", wallet.get_address(0, 0)?);

    // Initialize the wallet.
    let config = WalletConfig {
        daemon_address: "http://localhost:38081".to_string(),
        upper_transaction_size_limit: 10000, // TODO: use sane value.
        daemon_username: "".to_string(),
        daemon_password: "".to_string(),
        use_ssl: false,
        light_wallet: false,
        proxy_address: "".to_string(),
    };

    // Set WalletManager's daemon address
    manager.set_daemon_address(&config.daemon_address);

    // Perform the initialization.
    wallet.init(config)?;
    wallet.throw_if_error()?;

    let target_block = manager.get_height_target()?;
    println!("Target block: {}", target_block);

    // Refresh the wallet.
    wallet.refresh()?; // This calls MONERO_Wallet_startRefresh
    wallet.throw_if_error()?;

    // Wait for the refresh to complete.
    loop {
        let height = wallet
            .get_current_sync_height() // This calls MONERO_Wallet_blockChainHeight
            .expect("Failed to get blockchain height");

        let daemon_height = wallet
            .get_daemon_height() // This calls MONERO_Wallet_daemonBlockChainHeight
            .expect("Failed to get daemon height");

        println!("Current blockchain height: {} / {}", height, daemon_height);
        if height >= daemon_height {
            // After this height we can get_balance.
            break ();
        }
        // Wait one second.
        std::thread::sleep(std::time::Duration::from_secs(1));
    }

    // Get the balance.
    let balance_result = wallet.get_balance(0); // Account index 0.
    let balance = balance_result.unwrap();
    println!("Balance: {:?}", balance);

    // Clean up the wallet.
    std::fs::remove_file(wallet_str).expect("Failed to delete test wallet");
    std::fs::remove_file(format!("{}.keys", wallet_str))
        .expect("Failed to delete test wallet keys");

    Ok(())
}
2025-01-07 11:54:36,507 D Device 0 Created
2025-01-07 11:54:36,508 T refreshThreadFunc: starting refresh thread
2025-01-07 11:54:36,508 T refreshThreadFunc: waiting for refresh...
2025-01-07 11:54:36,548 I caching ringdb key
2025-01-07 11:54:36,562 D Calculated blockchain height: 1766275
2025-01-07 11:54:36,563 D Reconnecting...
2025-01-07 11:54:36,564 D Some problems at connect, message: resolve: Host not found (authoritative) [asio.netdb:1 at /Users/****/Development/monero_c/contrib/depends/aarch64-apple-darwin/include/boost/asio/detail/resolver_service.hpp:84:33 in function 'resolve']
2025-01-07 11:54:36,564 D Failed to connect to :
2025-01-07 11:54:36,564 I Failed to invoke http request to  /json_rpc
2025-01-07 11:54:36,564 E Failed to connect to daemon
2025-01-07 11:54:36,564 D Reconnecting...
2025-01-07 11:54:36,564 D Some problems at connect, message: resolve: Host not found (authoritative) [asio.netdb:1 at /Users/****/Development/monero_c/contrib/depends/aarch64-apple-darwin/include/boost/asio/detail/resolver_service.hpp:84:33 in function 'resolve']
2025-01-07 11:54:36,564 D Failed to connect to :
2025-01-07 11:54:36,564 I Failed to invoke http request to  /json_rpc
2025-01-07 11:54:36,564 E Failed to connect to daemon
2025-01-07 11:54:36,590 D /var/folders/q3/96gvm8255230tvzw3szbj0yr0000gn/T/.tmp0hltdN/test_wallet.keys is already unlocked.
Wallet created successfully.
Primary address: 56HeZM3u6xYCV8oVVh7CuWWHs7yeB1oxhNPrsEM5FKSqadTXmobLqsNEtRnyGsbN1rbDuBtWdtxtXhTJda1Lm9vcH73iSWn
2025-01-07 11:54:36,731 I [PARSE URI] regex not matched for uri: ^(([^:]*?)://)?(\[(.*)\](:(\d+))?)(.*)?
2025-01-07 11:54:36,731 I Generating SSL certificate
...
Current blockchain height: 1 / 1769997
Current blockchain height: 1769997 / 1769997

I still haven't gotten the syncing to work. Not sure why. It's also syncing way too fast. Either the restore height is not being set correctly or we are not actually syncing but only polling blocks?

Syncing works now.

I'm trying to move from a HTTP call to check_tx_key to a C call to MONERO_Wallet_checkTxKey. However I'm a bit unsure why there is a difference between the two. check_tx_key takes a txid, tx_key and address and gives me back confirmations and the received amount. MONERO_Wallet_checkTxKey however takes all 5 and only returns a boolean?

https://github.com/monero-project/monero/blob/1bd57c8e959d80d7f6cb21a0e560958c21c5d693/src/wallet/api/wallet2_api.h#L1026

extern ADDAPI bool MONERO_Wallet_checkTxKey(void* wallet_ptr, const char* txid, const char* tx_key, const char* address, uint64_t received, bool in_pool, uint64_t confirmations);
// virtual std::string getTxProof(const std::string &txid, const std::string &address, const std::string &message) const = 0;

@binarybaron
Copy link
Copy Markdown
Collaborator

binarybaron commented Jan 21, 2025

I wrote a patch to fix this. Haven't tested it yet though.

commit aa077a8a0578ee668ce47a8da2541823c4ecaff4
Author: Binarybaron <binarybaron@protonmail.com>
Date:   Tue Jan 21 15:13:45 2025 +0100

    fix(monero_c): Let MONERO_Wallet_checkTxKey take a reference instead of a value for received, in_pool, confirmations
    
    use pointer instead of reference

diff --git a/impls/monero.rs/src/bindings.rs b/impls/monero.rs/src/bindings.rs
index ebd0d47..1d0aa5b 100644
--- a/impls/monero.rs/src/bindings.rs
+++ b/impls/monero.rs/src/bindings.rs
@@ -1238,9 +1238,9 @@ extern "C" {
         txid: *const ::std::os::raw::c_char,
         tx_key: *const ::std::os::raw::c_char,
         address: *const ::std::os::raw::c_char,
-        received: u64,
-        in_pool: bool,
-        confirmations: u64,
+        received: *mut u64,
+        in_pool: *mut bool,
+        confirmations: *mut u64,
     ) -> bool;
 }
 extern "C" {
diff --git a/impls/monero.rs/src/lib.rs b/impls/monero.rs/src/lib.rs
index d8167bb..bb17e52 100644
--- a/impls/monero.rs/src/lib.rs
+++ b/impls/monero.rs/src/lib.rs
@@ -1445,16 +1445,17 @@ impl Wallet {
                 c_txid.as_ptr(),
                 c_tx_key.as_ptr(),
                 c_address.as_ptr(),
-                received_val,
-                in_pool_val,
-                confirmations_val,
+                &mut received_val,
+                &mut in_pool_val,
+                &mut confirmations_val,
             )
         };
 
         if result {
             Ok(CheckTxKey {
-                valid: true,
-                error: None,
+                received: received_val,
+                in_pool: in_pool_val,
+                confirmations: confirmations_val,
             })
         } else {
             // Retrieve the last error.
diff --git a/monero_libwallet2_api_c/src/main/cpp/wallet2_api_c.cpp b/monero_libwallet2_api_c/src/main/cpp/wallet2_api_c.cpp
index 0617a97..2672230 100644
--- a/monero_libwallet2_api_c/src/main/cpp/wallet2_api_c.cpp
+++ b/monero_libwallet2_api_c/src/main/cpp/wallet2_api_c.cpp
@@ -1972,16 +1972,27 @@ const char* MONERO_Wallet_getTxKey(void* wallet_ptr, const char* txid) {
     DEBUG_END()
 }
 
-bool MONERO_Wallet_checkTxKey(void* wallet_ptr, const char* txid, const char* tx_key, const char* address, uint64_t received, bool in_pool, uint64_t confirmations) {
-    Monero::Wallet* wallet = reinterpret_cast<Monero::Wallet*>(wallet_ptr);
-    bool result = wallet->checkTxKey(
-            std::string(txid),
-            std::string(tx_key),
-            std::string(address),
-            received,
-            in_pool,
-            confirmations
-    );
+bool MONERO_Wallet_checkTxKey(void* wallet_ptr,
+                              const char* txid,
+                              const char* tx_key,
+                              const char* address,
+                              uint64_t* received,
+                              bool* in_pool,
+                              uint64_t* confirmations) {
+    Monero::Wallet *wallet = reinterpret_cast<Monero::Wallet *>(wallet_ptr);
+
+    // Create local references from the pointers.
+    uint64_t &received_ref = *received;
+    bool &in_pool_ref = *in_pool;
+    uint64_t &confirmations_ref = *confirmations;
+
+    bool result = wallet->checkTxKey( std::string(txid),
+                                      std::string(tx_key),
+                                      std::string(address),
+                                      received_ref,
+                                      in_pool_ref,
+                                      confirmations_ref );
+
     return result;
 }
 
diff --git a/monero_libwallet2_api_c/src/main/cpp/wallet2_api_c.h b/monero_libwallet2_api_c/src/main/cpp/wallet2_api_c.h
index a0094b7..10b1cc9 100644
--- a/monero_libwallet2_api_c/src/main/cpp/wallet2_api_c.h
+++ b/monero_libwallet2_api_c/src/main/cpp/wallet2_api_c.h
@@ -778,7 +778,7 @@ extern ADDAPI const char* MONERO_Wallet_getUserNote(void* wallet_ptr, const char
 //     virtual std::string getTxKey(const std::string &txid) const = 0;
 extern ADDAPI const char* MONERO_Wallet_getTxKey(void* wallet_ptr, const char* txid);
 //     virtual bool checkTxKey(const std::string &txid, std::string tx_key, const std::string &address, uint64_t &received, bool &in_pool, uint64_t &confirmations) = 0;
-extern ADDAPI bool MONERO_Wallet_checkTxKey(void* wallet_ptr, const char* txid, const char* tx_key, const char* address, uint64_t received, bool in_pool, uint64_t confirmations);
+extern ADDAPI bool MONERO_Wallet_checkTxKey(void* wallet_ptr, const char* txid, const char* tx_key, const char* address, uint64_t* received, bool* in_pool, uint64_t* confirmations);
 //     virtual std::string getTxProof(const std::string &txid, const std::string &address, const std::string &message) const = 0;
 //     virtual bool checkTxProof(const std::string &txid, const std::string &address, const std::string &message, const std::string &signature, bool &good, uint64_t &received, bool &in_pool, uint64_t &confirmations) = 0;
 //     virtual std::string getSpendProof(const std::string &txid, const std::string &message) const = 0;

@MrCyjaneK
Copy link
Copy Markdown
Owner Author

I'm trying to move from a HTTP call to check_tx_key to a C call to MONERO_Wallet_checkTxKey. However I'm a bit unsure why there is a difference between the two. check_tx_key takes a txid, tx_key and address and gives me back confirmations and the received amount. MONERO_Wallet_checkTxKey however takes all 5 and only returns a boolean?

I'm not sure.. it's just wallet2_api.h, but if it takes a pointer it may as well return some data there.

Sorry for being offline, last 2 were rough - I am back now.

Are there any recurring issues or things that need solving? I'll be taking look at the linking issue this weekend to make sure that it works out of the box without weird hacks and copying.

@sneurlax
Copy link
Copy Markdown
Collaborator

I'd like to help check and test things as needed--if needed, anyways :) it seems y'all have things covered following #67 (which can be closed now, right, as this is the most up-to-date Rust impl?)

@binarybaron
Copy link
Copy Markdown
Collaborator

I'd like to help check and test things as needed--if needed, anyways :) it seems y'all have things covered following #67 (which can be closed now, right, as this is the most up-to-date Rust impl?)

We built our own wrapper that does not depend on the monero_c interop layer. The interop layer is dynamically generated by cxx. This simplifies the whole setup massively.

eigenwallet/core#303

But we've adopted a bunch of the patterns from this PR. Your work is still appreciated 🙏 If you're interested in contributing you could help us with getting it all to build on the different platforms. I'm sure you have more experience with the Monero build system than we do.

@MrCyjaneK
Copy link
Copy Markdown
Owner Author

@sneurlax I had no time (and not much knowledge on rust) to finish this PR on my own, it is probably left in pretty much the same state as you last remember :p - if there is anything I can do from C/C++ side then I'm happy to help

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants