diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 1f3f359..54bd6c2 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -1849,7 +1849,7 @@ dependencies = [ [[package]] name = "silentdragonlitelib" version = "0.1.0" -source = "git+https://git.hush.is/lucretius/silentdragonlite-cli?rev=eff5dd7b6dbcfd7e4db6fdba423399337b590722#eff5dd7b6dbcfd7e4db6fdba423399337b590722" +source = "git+https://git.hush.is/lucretius/silentdragonlite-cli?rev=2483d4f372079ee8cb00a61caba74b53e4fcf1e3#2483d4f372079ee8cb00a61caba74b53e4fcf1e3" dependencies = [ "base58", "bellman", diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 4d3007a..639c0ad 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -12,4 +12,4 @@ crate-type = ["staticlib"] libc = "0.2.58" lazy_static = "1.4.0" blake3 = "0.3.4" -silentdragonlitelib = { git = "https://git.hush.is/lucretius/silentdragonlite-cli", rev = "eff5dd7b6dbcfd7e4db6fdba423399337b590722" } +silentdragonlitelib = { git = "https://git.hush.is/lucretius/silentdragonlite-cli", rev = "2483d4f372079ee8cb00a61caba74b53e4fcf1e3" } diff --git a/lib/src/lib.rs b/lib/src/lib.rs index eaa03ba..eb3cf53 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -6,6 +6,7 @@ use libc::{c_char}; use std::ffi::{CStr, CString}; use std::sync::{Mutex, Arc}; use std::cell::RefCell; +use std::ptr; use silentdragonlitelib::{commands, lightclient::{LightClient, LightClientConfig}}; @@ -109,33 +110,44 @@ pub extern fn litelib_initialize_new(dangerous: bool,server: *const c_char) -> * /// Restore a wallet from the seed phrase #[no_mangle] -pub extern fn litelib_initialize_new_from_phrase(dangerous: bool,server: *const c_char, +pub extern "C" fn litelib_initialize_new_from_phrase(dangerous: bool, server: *const c_char, seed: *const c_char, birthday: u64, number: u64, overwrite: bool) -> *mut c_char { - let server_str = unsafe { - assert!(!server.is_null()); + // Prüfen auf null-Pointer + if server.is_null() || seed.is_null() { + println!("Server or seed is null"); + return ptr::null_mut(); + } + let server_str = unsafe { CStr::from_ptr(server).to_string_lossy().into_owned() }; - let seed_str = unsafe { - assert!(!seed.is_null()); - CStr::from_ptr(seed).to_string_lossy().into_owned() }; + println!("Initializing with server: {}, seed: {}", server_str, seed_str); + let server = LightClientConfig::get_server_or_default(Some(server_str)); - let (config, _latest_block_height) = match LightClientConfig::create(server,dangerous) { - Ok((c, h)) => (c, h), + let (config, _latest_block_height) = match LightClientConfig::create(server, dangerous) { + Ok((c, h)) => { + println!("Config created successfully"); + (c, h) + }, Err(e) => { - let e_str = CString::new(format!("Error: {}", e)).unwrap(); + println!("Error creating config: {}", e); + let e_str = CString::new(format!("Error: {}", e)).unwrap_or_else(|_| CString::new("Error creating CString").unwrap()); return e_str.into_raw(); } }; let lightclient = match LightClient::new_from_phrase(seed_str, &config, birthday, number, overwrite) { - Ok(l) => l, + Ok(l) => { + println!("LightClient created successfully"); + l + }, Err(e) => { - let e_str = CString::new(format!("Error: {}", e)).unwrap(); + println!("Error creating LightClient: {}", e); + let e_str = CString::new(format!("Error: {}", e)).unwrap_or_else(|_| CString::new("Error creating CString").unwrap()); return e_str.into_raw(); } }; @@ -145,18 +157,17 @@ pub extern fn litelib_initialize_new_from_phrase(dangerous: bool,server: *const let lc = Arc::new(lightclient); match LightClient::start_mempool_monitor(lc.clone()) { - Ok(_) => {println!("Starting Mempool")}, - Err(e) => { - println!("Couldnt start mempool {}",e) - } + Ok(_) => println!("Starting Mempool"), + Err(e) => println!("Could not start mempool: {}", e) } LIGHTCLIENT.lock().unwrap().replace(Some(lc)); - - let c_str = CString::new("OK").unwrap(); + + let c_str = CString::new("OK").unwrap_or_else(|_| CString::new("CString creation failed").unwrap()); return c_str.into_raw(); } + // Initialize a new lightclient and store its value #[no_mangle] pub extern fn litelib_initialize_existing(dangerous: bool, server: *const c_char) -> *mut c_char { diff --git a/src/connection.cpp b/src/connection.cpp index 16f89ea..e96651a 100644 --- a/src/connection.cpp +++ b/src/connection.cpp @@ -105,15 +105,15 @@ void ConnectionLoader::ShowProgress() DEBUG("server=" << config->server << " connection=" << connection << " me=" << me); isSyncing = new QAtomicInteger(); - isSyncing->store(true); + isSyncing->storeRelaxed(true); DEBUG("isSyncing"); // Do a sync after import syncTimer = new QTimer(main); DEBUG("Beginning sync after import wif"); connection->doRPC("sync", "", [=](auto) { - DEBUG("finished syncing"); - isSyncing->store(false); + qDebug()<< "finished syncing"; + isSyncing->storeRelaxed(false); // Cancel the timer syncTimer->deleteLater(); // When sync is done, set the connection @@ -125,7 +125,7 @@ void ConnectionLoader::ShowProgress() // While it is syncing, we'll show the status updates while it is alive. QObject::connect(syncTimer, &QTimer::timeout, [=]() { DEBUG("Check the sync status"); - if (isSyncing != nullptr && isSyncing->load()) { + if (isSyncing != nullptr && isSyncing->loadRelaxed()) { DEBUG("Get the sync status"); try { connection->doRPC("syncstatus", "", [=](json reply) { @@ -220,7 +220,7 @@ void ConnectionLoader::doAutoConnect() auto connection = makeConnection(config); auto me = this; qDebug() << __func__ << ": server=" << config->server - << " connection=" << connection << " me=" << me << endl; + << " connection=" << connection << " me=" << me << Qt::endl; // After the lib is initialized, try to do get info connection->doRPC("info", "", [=](auto reply) { @@ -229,15 +229,15 @@ void ConnectionLoader::doAutoConnect() connection->setInfo(reply); DEBUG("getting Connection reply"); isSyncing = new QAtomicInteger(); - isSyncing->store(true); + isSyncing->storeRelaxed(true); DEBUG("isSyncing"); // Do a sync at startup syncTimer = new QTimer(main); DEBUG("Beginning sync"); connection->doRPC("sync", "", [=](auto) { - DEBUG("finished syncing"); - isSyncing->store(false); + qDebug()<<"finished syncing startup"; + isSyncing->storeRelaxed(false); // Cancel the timer syncTimer->deleteLater(); // When sync is done, set the connection @@ -252,9 +252,9 @@ void ConnectionLoader::doAutoConnect() // auto connection = makeConnection(config); // DEBUG("changed server to " << config->server); connection->doRPC("sync", "", [=](auto) mutable { - DEBUG("sync success with server=" << config->server); + qDebug()<<"sync success with server=" << config->server; failed = false; - isSyncing->store(false); + isSyncing->storeRelaxed(false); // Cancel the timer syncTimer->deleteLater(); // When sync is done, set the connection @@ -268,7 +268,7 @@ void ConnectionLoader::doAutoConnect() // While it is syncing, we'll show the status updates while it is alive. QObject::connect(syncTimer, &QTimer::timeout, [=]() { DEBUG("Check the sync status"); - if (isSyncing != nullptr && isSyncing->load()) { + if (isSyncing != nullptr && isSyncing->loadRelaxed()) { DEBUG("Getting the sync status"); try { connection->doRPC("syncstatus", "", [=](json reply) { diff --git a/src/controller.cpp b/src/controller.cpp index ec2e013..7a6e957 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -9,6 +9,9 @@ #include "camount.h" #include "Model/ChatItem.h" #include "DataStore/DataStore.h" +#include +#include +#include ChatModel *chatModel = new ChatModel(); Chat *chat = new Chat(); @@ -127,117 +130,124 @@ void Controller::setConnection(Connection* c) // Build the RPC JSON Parameters for this tx void Controller::fillTxJsonParams(json& allRecepients, Tx tx) { - Q_ASSERT(allRecepients.is_array()); + Q_ASSERT(allRecepients.is_array()); - // Construct the JSON params - json rec = json::object(); + // Variablen zur Speicherung der Adresse mit dem höchsten Gesamtwert + std::string addressWithMaxValue; + int maxValue = 0; + std::map addressValues; - //creating the JSON dust parameters in a std::vector to iterate over there during tx - std::vector dust(8); - dust.resize(8, json::object()); + // Zähle die Anzahl der spendablen Notizen mit einem Wert über 10.000 + int spendableNotesCount = 0; + bool replaceDustTransaction = false; // Standardmäßig keine Ersetzung - // Create Sietch zdust addr again to not use it twice. - // Using DataStore singelton, to store the data outside of lambda, bing bada boom :D - for(uint8_t i = 0; i < 8; i++) - { - zrpc->createNewSietchZaddr( [=] (json reply) { - QString zdust = QString::fromStdString(reply.get()[0]); - DataStore::getSietchDataStore()->setData(QString("Sietch") + QString(i), zdust.toUtf8()); - } ); - } - // Set sietch zdust addr to json. - // Using DataStore singelton, to store the data into the dust. - for(uint8_t i = 0; i < 8; i++) - { - dust.at(i)["address"] = DataStore::getSietchDataStore()->getData(QString("Sietch" + QString(i))).toStdString(); - } + std::promise fetchPromise; + std::future fetchFuture = fetchPromise.get_future(); - DataStore::getSietchDataStore()->clear(); // clears the datastore - - const QString possibleCharacters("0123456789abcdef"); - int sizerandomString = 512; - const int randomStringLength = sizerandomString; + zrpc->fetchUnspent([=, &spendableNotesCount, &replaceDustTransaction, &addressValues, &addressWithMaxValue, &maxValue, &fetchPromise] (json reply) { + // Fehlerbehandlung hinzugefügt + if (reply.find("unspent_notes") == reply.end() || !reply["unspent_notes"].is_array()) { + qDebug() << "Fehler: 'unspent_notes' fehlt oder ist kein Array"; + fetchPromise.set_value(); + return; + } + + // Bearbeite die Antwort - for(uint8_t i = 0; i < 8; i++) { - QString randomString; - QRandomGenerator *gen = QRandomGenerator::system(); + for (const auto& note : reply["unspent_notes"]) { + if (note.find("spendable") != note.end() && note.find("value") != note.end() && + note["spendable"].is_boolean() && note["value"].is_number_integer()) { - for(int i=0; ibounded(0, possibleCharacters.length() - 1); - QChar nextChar = possibleCharacters.at(index); - randomString.append(nextChar); + if (note["spendable"] && note["value"] >= 10000) { + spendableNotesCount++; + } + + std::string address = note["address"]; + int value = note["value"]; + addressValues[address] += value; + if (addressValues[address] > maxValue) { + maxValue = addressValues[address]; + addressWithMaxValue = address; + } + } } - dust.at(i)["memo"] = randomString.toStdString(); + replaceDustTransaction = spendableNotesCount < 10; + qDebug() << "Nutzbare Notes Anzahl : " << spendableNotesCount; + fetchPromise.set_value(); + }); + + fetchFuture.wait(); // Warte auf die Fertigstellung des fetchUnspent-Aufrufs + // Erstelle die Staubtransaktionen + std::vector dust(8, json::object()); + + // Promises und Futures für die asynchronen Aufrufe + std::vector> promises(8); + std::vector> futures; + for (int i = 0; i < 8; i++) { + futures.push_back(promises[i].get_future()); + + zrpc->createNewSietchZaddr([=, &promises] (json reply) { + promises[i].set_value(reply); + }); } - for(auto &it: dust) - { + // Warte auf die Fertigstellung aller Futures + for (auto& future : futures) { + future.wait(); + } + + // Verarbeite die Ergebnisse der Futures + for (int i = 0; i < 8; i++) { + json reply = futures[i].get(); // Hier erhalten wir das Ergebnis + std::string zdust = reply[0]; + dust.at(i)["address"] = zdust; + } + + // Setze Staubtransaktionen + for(auto &it: dust) { it["amount"] = 0; } - - // For each addr/amt/memo, construct the JSON and also build the confirm dialog box - for (int i=0; i < tx.toAddrs.size(); i++) - { - auto toAddr = tx.toAddrs[i]; + + // Generiere zufälliges Memo + const QString possibleCharacters("0123456789abcdef"); + const int randomStringLength = 512; // Länge des zufälligen Strings + QString randomString; + + for(int i = 0; i < randomStringLength; ++i) { + int index = QRandomGenerator::global()->bounded(possibleCharacters.length()); + randomString.append(possibleCharacters.at(index)); + } + + // Füge Transaktionen hinzu + json rec = json::object(); + for (int i = 0; i < tx.toAddrs.size(); i++) { + auto toAddr = tx.toAddrs[i]; rec["address"] = toAddr.addr.toStdString(); - rec["amount"] = toAddr.amount.toqint64(); + rec["amount"] = toAddr.amount.toqint64(); if (Settings::isZAddress(toAddr.addr) && !toAddr.memo.trimmed().isEmpty()) rec["memo"] = toAddr.memo.toStdString(); allRecepients.push_back(rec); } - int decider = rand() % 100 + 1 ; ; // random int between 1 and 100 + // Entscheide, ob eine Staubtransaktion ersetzt werden soll + if (replaceDustTransaction) { + int dustIndexToReplace = rand() % dust.size(); // Zufälliger Index + auto& dustTransactionToReplace = dust.at(dustIndexToReplace); + dustTransactionToReplace["address"] = addressWithMaxValue; // Adresse mit dem höchsten Gesamtwert + dustTransactionToReplace["amount"] = 10000; + dustTransactionToReplace["memo"] = randomString.toStdString(); + } - if (tx.toAddrs.size() < 2) { - - if(decider % 4 == 3) { - allRecepients.insert(std::begin(allRecepients), { - dust.at(0), - dust.at(1), - dust.at(2), - dust.at(3), - dust.at(4), - dust.at(5) - }) ; - - } else { - allRecepients.insert(std::begin(allRecepients), { - dust.at(0), - dust.at(1), - dust.at(2), - dust.at(3), - dust.at(4), - dust.at(5), - dust.at(6) - }) ; - } - } else { - - if(decider % 4 == 3) { - allRecepients.insert(std::begin(allRecepients), { - dust.at(0), - dust.at(1), - dust.at(2), - dust.at(3), - dust.at(4) - }) ; - } else { - allRecepients.insert(std::begin(allRecepients), { - dust.at(0), - dust.at(1), - dust.at(2), - dust.at(3), - dust.at(4), - dust.at(5) - }) ; - } + // Füge Staubtransaktionen einzeln hinzu + for (const auto& dustTransaction : dust) { + allRecepients.push_back(dustTransaction); } +} -} void Controller::noConnection() { diff --git a/src/firsttimewizard.cpp b/src/firsttimewizard.cpp index 5ed065f..857e77a 100644 --- a/src/firsttimewizard.cpp +++ b/src/firsttimewizard.cpp @@ -725,41 +725,40 @@ bool RestoreSeedPage::validatePage() { return false; } - ///Number - QString number_str = form.number->text(); - qint64 number = number_str.toUInt(); - // 3. Attempt to restore wallet with the seed phrase - { - QString reply = ""; - try { - char* resp = litelib_initialize_new_from_phrase(parent->dangerous, parent->server.toStdString().c_str(), - seed.toStdString().c_str(), birthday, number); - reply = litelib_process_response(resp); - } catch (const std::exception& e) { - qDebug() << __func__ << ": caught an exception, ignoring: " << e.what(); - } +// 3. Initialize wallet with number + QString number_str = form.number->text(); + qint64 number = number_str.toUInt(); + qDebug() << __func__ << ": Initializing wallet with number: " << number; - qDebug() << __func__ << ": reply=" << reply; + QString reply = ""; +try { + char *resp = litelib_initialize_new_from_phrase(parent->dangerous, parent->server.toStdString().c_str(), + seed.toStdString().c_str(), birthday, number); - if (reply.toUpper().trimmed() != "OK") { - qDebug() << "Lite server " << parent->server << " is down, getting a random one"; - parent->server = Settings::getRandomServer(); - qDebug() << __func__ << ": new server is " << parent->server; + if (resp != nullptr) { + reply = litelib_process_response(resp); + } else { + qDebug() << __func__ << ": Null response from litelib_initialize_new_from_phrase"; + } +} catch (const std::exception &e) { + qDebug() << __func__ << ": caught an exception, ignoring: " << e.what(); +} - // retry with the new server - char* resp = litelib_initialize_new_from_phrase(parent->dangerous, parent->server.toStdString().c_str(), - seed.toStdString().c_str(), birthday, number); - reply = litelib_process_response(resp); - } + qDebug() << __func__ << ": reply=" << reply; +if (reply.toUpper().trimmed() != "OK") { + qDebug() << "Lite server " << parent->server << " is down, getting a random one"; + parent->server = Settings::getRandomServer(); + qDebug() << __func__ << ": new server is " << parent->server; - if (reply.toUpper().trimmed() != "OK") { - QMessageBox::warning(this, tr("Failed to restore wallet"), - tr("Couldn't restore the wallet") + "\n" + "server=" + parent->server + "\n" + reply, - QMessageBox::Ok); - return false; - } + char *resp = litelib_initialize_new_from_phrase(parent->dangerous, parent->server.toStdString().c_str(), + seed.toStdString().c_str(), birthday, number); + if (resp != nullptr) { + reply = litelib_process_response(resp); + } else { + qDebug() << __func__ << ": Null response on retry from litelib_initialize_new_from_phrase"; } +} // 4. Finally attempt to save the wallet {