diff --git a/lib/Cargo.lock b/lib/Cargo.lock index a7884bb..2166ad1 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/hush/silentdragonlite-cli?rev=4ec78a01b4f35b08eff42b10e3be85de87ba2b02#4ec78a01b4f35b08eff42b10e3be85de87ba2b02" +source = "git+https://git.hush.is/hush/silentdragonlite-cli?rev=568d7b7860ec0b848cb84474f38b25bed890de09#568d7b7860ec0b848cb84474f38b25bed890de09" dependencies = [ "base58", "bellman", diff --git a/lib/Cargo.toml b/lib/Cargo.toml index a500de6..2bc90af 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/hush/silentdragonlite-cli", rev = "4ec78a01b4f35b08eff42b10e3be85de87ba2b02" } +silentdragonlitelib = { git = "https://git.hush.is/hush/silentdragonlite-cli", rev = "568d7b7860ec0b848cb84474f38b25bed890de09" } diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 7db5dd8..d78c23d 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}}; @@ -108,33 +109,43 @@ 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()); + 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(); } }; @@ -144,15 +155,13 @@ 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(); } @@ -185,7 +194,6 @@ pub extern fn litelib_initialize_existing(dangerous: bool, server: *const c_char // Initialize logging let _ = lightclient.init_logging(); - let lc = Arc::new(lightclient); match LightClient::start_mempool_monitor(lc.clone()) { Ok(_) => {println!("Starting Mempool")}, diff --git a/silentdragon-lite.pro b/silentdragon-lite.pro index 0faf9f2..49223eb 100644 --- a/silentdragon-lite.pro +++ b/silentdragon-lite.pro @@ -73,6 +73,7 @@ SOURCES += \ src/DataStore/DataStore.cpp \ src/DataStore/ChatDataStore.cpp \ src/DataStore/SietchDataStore.cpp \ + src/DataStore/NoteCountDataStore.cpp \ src/DataStore/ContactDataStore.cpp \ src/Model/ChatItem.cpp \ src/Model/ContactRequestChatItem.cpp \ diff --git a/src/Chat/Chat.cpp b/src/Chat/Chat.cpp index 08dbd08..c1815b6 100644 --- a/src/Chat/Chat.cpp +++ b/src/Chat/Chat.cpp @@ -93,7 +93,7 @@ void Chat::renderChatBox(Ui::MainWindow *ui, QListView *view, QLabel *label) DataStore::getChatDataStore()->dump(); // test to see if the chat items in datastore are correctly dumped to json std::map seenTxids; - qDebug() << __func__ << ": looking at memos..."; + //qDebug() << __func__ << ": looking at memos..."; for (auto &contact : AddressBook::getInstance()->getAllAddressLabels()) { for (auto &memo : DataStore::getChatDataStore()->getAllMemos()) { @@ -104,7 +104,7 @@ void Chat::renderChatBox(Ui::MainWindow *ui, QListView *view, QLabel *label) QStandardItem *Items = new QStandardItem(memo.second.toChatLine()); Items->setData(OUTGOING, Qt::UserRole + 1); - qDebug() << __func__ << ": appending row to OUTGOING chatitems to contact " << contact.getName() << " with item " << Items; + // qDebug() << __func__ << ": appending row to OUTGOING chatitems to contact " << contact.getName() << " with item " << Items; chat->appendRow(Items); ui->listChat->setModel(chat); @@ -112,7 +112,7 @@ void Chat::renderChatBox(Ui::MainWindow *ui, QListView *view, QLabel *label) ui->listChat->setModel(chat); } - qDebug() << __func__ << ": memo.first=" << memo.first; + // qDebug() << __func__ << ": memo.first=" << memo.first; if ( (contact.getName() == ui->contactNameMemo->text().trimmed()) && (contact.getMyAddress() == memo.second.getAddress()) && (memo.second.isOutgoing() == false) && @@ -120,19 +120,19 @@ void Chat::renderChatBox(Ui::MainWindow *ui, QListView *view, QLabel *label) ) { QStandardItem *Items1 = new QStandardItem(memo.second.toChatLine()); Items1->setData(INCOMING, Qt::UserRole + 1); - qDebug() << __func__ << ": appending row to INCOMING chatitems to contact " << contact.getName() << "with txid=" << memo.second.getTxid() << " cid=" << contact.getCid() << " item " << Items1 << " memo=" << memo.second.getMemo(); + // qDebug() << __func__ << ": appending row to INCOMING chatitems to contact " << contact.getName() << "with txid=" << memo.second.getTxid() << " cid=" << contact.getCid() << " item " << Items1 << " memo=" << memo.second.getMemo(); if(seenTxids.count( memo.second.getTxid() ) > 0) { // Do not render the same chat multiple times // TODO: this should also look at outputindex to allow for multi-part memos, when that is supported - qDebug() << __func__ << ": INCOMING ignoring txid=" << memo.second.getTxid(); + // qDebug() << __func__ << ": INCOMING ignoring txid=" << memo.second.getTxid(); continue; } // TODO: better header memo detection if (memo.second.getMemo().startsWith("{")) { - qDebug() << __func__ << ": ignoring header memo=" << memo.second.getMemo(); + // qDebug() << __func__ << ": ignoring header memo=" << memo.second.getMemo(); } else { chat->appendRow(Items1); ui->listChat->setModel(chat); diff --git a/src/DataStore/DataStore.cpp b/src/DataStore/DataStore.cpp index f7aa1a4..c90bc88 100644 --- a/src/DataStore/DataStore.cpp +++ b/src/DataStore/DataStore.cpp @@ -7,6 +7,11 @@ SietchDataStore* DataStore::getSietchDataStore() return SietchDataStore::getInstance(); } +NoteCountDataStore* DataStore::getNoteCountDataStore() +{ + return NoteCountDataStore::getInstance(); +} + ChatDataStore* DataStore::getChatDataStore() { return ChatDataStore::getInstance(); diff --git a/src/DataStore/DataStore.h b/src/DataStore/DataStore.h index 14df162..ee1ef47 100644 --- a/src/DataStore/DataStore.h +++ b/src/DataStore/DataStore.h @@ -4,6 +4,7 @@ #define DATASTORE_H #include "SietchDataStore.h" +#include "NoteCountDataStore.h" #include "ChatDataStore.h" #include "ContactDataStore.h" @@ -11,6 +12,7 @@ class DataStore { public: static SietchDataStore* getSietchDataStore(); + static NoteCountDataStore* getNoteCountDataStore(); static ChatDataStore* getChatDataStore(); static ContactDataStore* getContactDataStore(); }; diff --git a/src/DataStore/NoteCountDataStore.cpp b/src/DataStore/NoteCountDataStore.cpp new file mode 100644 index 0000000..7575d72 --- /dev/null +++ b/src/DataStore/NoteCountDataStore.cpp @@ -0,0 +1,51 @@ +#include "NoteCountDataStore.h" + +NoteCountDataStore* NoteCountDataStore::instance = nullptr; +bool NoteCountDataStore::instanced = false; + +NoteCountDataStore* NoteCountDataStore::getInstance() { + if (!instanced) { + instanced = true; + instance = new NoteCountDataStore(); + } + return instance; +} + +void NoteCountDataStore::clear() { + data.clear(); +} + +void NoteCountDataStore::setData(const QString& key, const QString& value) { + data[key] = value; +} + +QString NoteCountDataStore::getData(const QString& key) { + return data.value(key); +} + +QString NoteCountDataStore::dump() { + QString result; + for (const auto& key : data.keys()) { + result += key + ": " + data[key] + "\n"; + } + return result; +} + +void NoteCountDataStore::setSpendableNotesCount(int count) { + spendableNotesCount = count; +} + +int NoteCountDataStore::getSpendableNotesCount() const { + return spendableNotesCount; +} + +void NoteCountDataStore::setAddressWithMaxValue(const QString& address, int value) { + if (value > maxValue) { + maxValue = value; + addressWithMaxValue = address; + } +} + +QString NoteCountDataStore::getAddressWithMaxValue() const { + return addressWithMaxValue; +} diff --git a/src/DataStore/NoteCountDataStore.h b/src/DataStore/NoteCountDataStore.h new file mode 100644 index 0000000..8b2913f --- /dev/null +++ b/src/DataStore/NoteCountDataStore.h @@ -0,0 +1,36 @@ +#ifndef NOTECOUNTDATASTORE_H +#define NOTECOUNTDATASTORE_H + +#include +#include + +class NoteCountDataStore { +private: + static NoteCountDataStore* instance; + static bool instanced; + QMap data; + int spendableNotesCount; + QString addressWithMaxValue; + int maxValue; // HinzugefĆ¼gt, um den maximalen Wert zu speichern + + NoteCountDataStore() : spendableNotesCount(0), maxValue(0) {} // Initialisiere maxValue + +public: + static NoteCountDataStore* getInstance(); + void clear(); + void setData(const QString& key, const QString& value); + QString getData(const QString& key); + QString dump(); + + void setSpendableNotesCount(int count); + int getSpendableNotesCount() const; + void setAddressWithMaxValue(const QString& address, int value); + QString getAddressWithMaxValue() const; + + ~NoteCountDataStore() { + instanced = false; + instance = nullptr; + } +}; + +#endif // NOTECOUNTDATASTORE_H diff --git a/src/addressbook.cpp b/src/addressbook.cpp index e57f160..67afada 100644 --- a/src/addressbook.cpp +++ b/src/addressbook.cpp @@ -304,7 +304,7 @@ void AddressBook::open(MainWindow* parent, QLineEdit* target) }); auto fnSetTargetLabelAddr = [=] (QLineEdit* target, QString label, QString addr, QString myAddr, QString cid, QString avatar) { - qDebug() << __func__ << ": label=" << label << " cid=" << cid << " avatar=" << avatar; + // qDebug() << __func__ << ": label=" << label << " cid=" << cid << " avatar=" << avatar; target->setText(label % "/" % addr % myAddr); }; diff --git a/src/chatmodel.cpp b/src/chatmodel.cpp index 4dedaa2..5f4a601 100644 --- a/src/chatmodel.cpp +++ b/src/chatmodel.cpp @@ -449,7 +449,7 @@ Tx MainWindow::createTxFromChatPage() { if (crypto_kx_seed_keypair(pk,sk, MESSAGEAS1) !=0) { this->logger->write("Suspicious keypair, bail out "); - qDebug() << __func__<< ": Suspicious client public outgoing key from crypto_kx_seed_keypair, aborting!"; + // qDebug() << __func__<< ": Suspicious client public outgoing key from crypto_kx_seed_keypair, aborting!"; return tx; } @@ -462,7 +462,7 @@ Tx MainWindow::createTxFromChatPage() { if (crypto_kx_server_session_keys(server_rx, server_tx, pk, sk, pubkeyBob) != 0) { this->logger->write("Suspicious client public send key, bail out "); - qDebug() << __func__ << ": Suspicious client public send key from crypto_kx_server_session_keys, aborting!"; + // << __func__ << ": Suspicious client public send key from crypto_kx_server_session_keys, aborting!"; return tx; } @@ -794,7 +794,7 @@ Tx MainWindow::createTxForSafeContactRequest() if (crypto_kx_seed_keypair(pk, sk, MESSAGEAS1) !=0) { this->logger->write("Suspicious client public contact request key, bail out "); - qDebug() << __func__ << ": Suspicious client public send key from crypto_kx_seed_keypair, aborting!"; + // qDebug() << __func__ << ": Suspicious client public send key from crypto_kx_seed_keypair, aborting!"; return tx; } diff --git a/src/connection.cpp b/src/connection.cpp index a5c3db4..ac1b0a1 100644 --- a/src/connection.cpp +++ b/src/connection.cpp @@ -34,7 +34,7 @@ ConnectionLoader::ConnectionLoader(MainWindow* main, Controller* rpc) connD->setupUi(d); auto theme = Settings::getInstance()->get_theme_name(); - DEBUG("theme " << theme << " has loaded"); + //DEBUG("theme " << theme << " has loaded"); auto size = QSize(512,512); if (theme == "Dark" || theme == "Midnight") { @@ -57,7 +57,7 @@ ConnectionLoader::ConnectionLoader(MainWindow* main, Controller* rpc) ConnectionLoader::~ConnectionLoader() { - DEBUG("destroying ConnectionLoader"); + // DEBUG("destroying ConnectionLoader"); delete isSyncing; delete connD; delete d; @@ -100,64 +100,62 @@ void ConnectionLoader::ShowProgress() config->dangerous = false; config->server = Settings::getInstance()->getSettings().server; + DEBUG("Creating connection with server=" << config->server); auto connection = makeConnection(config); - auto me = this; - DEBUG("server=" << config->server << " connection=" << connection << " me=" << me); + if (!connection) { + DEBUG("Failed to create connection"); + return; + } - isSyncing = new QAtomicInteger(); - isSyncing->store(true); - DEBUG("isSyncing"); + auto me = this; + isSyncing = new QAtomicInteger(true); + DEBUG("isSyncing set to true"); // Do a sync after import syncTimer = new QTimer(main); - DEBUG("Beginning sync after import wif"); + DEBUG("Created syncTimer"); connection->doRPC("sync", "", [=](auto) { - DEBUG("finished syncing"); - isSyncing->store(false); - // Cancel the timer + qDebug()<< "Finished syncing"; + isSyncing->storeRelaxed(false); syncTimer->deleteLater(); - // When sync is done, set the connection this->doRPCSetConnectionShield(connection); }, [=](auto) { DEBUG("sync rpc error! server=" << config->server); }); - // 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()) { - DEBUG("Get the sync status"); - try { - connection->doRPC("syncstatus", "", [=](json reply) { - if (isSyncing != nullptr && reply.find("synced_blocks") != reply.end()) { - qint64 synced = reply["synced_blocks"].get(); - qint64 total = reply["total_blocks"].get(); - me->showInformation( - "Syncing... " + QString::number(synced) + " / " + QString::number(total) - ); - } - }, [=](QString err) { - DEBUG("Sync error " << err); - // We may have gotten "Unexpected compression flag: 60" - // or some other error, so let's try another server - config->server = Settings::getRandomServer(); - DEBUG("Changed server to " << config->server ); - }); - } catch (const std::exception& e) { - DEBUG("syncstatus exception: " << e.what() ); - main->logger->write("catch sync progress reply"); + if (!isSyncing || !isSyncing->loadRelaxed()) { + DEBUG("Syncing complete or isSyncing is null, stopping timer"); + syncTimer->stop(); + return; + } - // rethrow exception so loadProgress can catch - // it and retry the entire ShowProgress() function again - throw new std::runtime_error(std::string("syncstatus failed")); - } + DEBUG("Checking sync status"); + try { + connection->doRPC("syncstatus", "", [=](json reply) { + if (isSyncing && reply.find("synced_blocks") != reply.end()) { + qint64 synced = reply["synced_blocks"].get(); + qint64 total = reply["total_blocks"].get(); + DEBUG("Sync status: " << synced << " / " << total); + me->showInformation( + "Syncing... " + QString::number(synced) + " / " + QString::number(total) + ); + } + }, [=](QString err) { + DEBUG("Sync status error: " << err); + config->server = Settings::getRandomServer(); + DEBUG("Changed server to " << config->server); + }); + } catch (const std::exception& e) { + DEBUG("Exception caught in syncstatus: " << e.what()); + throw; } }); - int interval = 1*1000; + int interval = 1 * 1000; syncTimer->setInterval(interval); syncTimer->start(); - DEBUG("Start sync timer with interval=" << interval); + DEBUG("Sync timer started with interval=" << interval); } void ConnectionLoader::doAutoConnect() @@ -165,10 +163,10 @@ void ConnectionLoader::doAutoConnect() auto config = std::shared_ptr(new ConnectionConfig()); config->dangerous = false; config->server = Settings::getInstance()->getSettings().server; - DEBUG(" server=" << config->server); + DEBUG("Creating connection with server=" << config->server); // Initialize the library - DEBUG("Attempting to initialize library with "<< config->server); + DEBUG("Attempting to initialize library with " << config->server); // Check to see if there's an existing wallet if (litelib_wallet_exists(Settings::getDefaultChainName().toStdString().c_str())) { @@ -219,56 +217,49 @@ void ConnectionLoader::doAutoConnect() auto connection = makeConnection(config); auto me = this; - qDebug() << __func__ << ": server=" << config->server - << " connection=" << connection << " me=" << me << endl; + qDebug() << __func__ << ": server=" << config->server + << " connection=" << connection << " me=" << me << Qt::endl; // After the lib is initialized, try to do get info connection->doRPC("info", "", [=](auto reply) { - // If success, set the connection DEBUG("Connection is online."); connection->setInfo(reply); DEBUG("getting Connection reply"); isSyncing = new QAtomicInteger(); - isSyncing->store(true); - DEBUG("isSyncing"); + isSyncing->storeRelaxed(true); + DEBUG("isSyncing set to true"); // Do a sync at startup syncTimer = new QTimer(main); - DEBUG("Beginning sync"); + DEBUG("Beginning sync at startup"); 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 this->doRPCSetConnection(connection); }, [=](auto) mutable { DEBUG("sync rpc error! server=" << config->server); - // continually retry sync RPC until it succeeds - // don't change server each time it fails - bool failed = true; - do { - // config->server = Settings::getRandomServer(); - // auto connection = makeConnection(config); - // DEBUG("changed server to " << config->server); + // Attempt to retry sync RPC with a delay + QTimer::singleShot(5000, [=]() { // 5-second delay connection->doRPC("sync", "", [=](auto) mutable { - DEBUG("sync success with server=" << config->server); - failed = false; - isSyncing->store(false); + qDebug()<<"sync success with server=" << config->server; + isSyncing->storeRelaxed(false); // Cancel the timer syncTimer->deleteLater(); // When sync is done, set the connection this->doRPCSetConnection(connection); }, [=](auto) { - DEBUG("sync failed with server=" << config->server << " . continuing sync loop" ); + DEBUG("sync failed with server=" << config->server << " . retrying after delay"); }); - } while (failed); + }); }); // 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) { @@ -380,7 +371,7 @@ void ConnectionLoader::showError(QString explanation) QString litelib_process_response(char* resp) { - qDebug() << __func__ << ": " << resp; + //qDebug() << __func__ << ": " << resp; char* resp_copy = new char[strlen(resp) + 1]; //a safer version of strcpy @@ -398,7 +389,7 @@ QString litelib_process_response(char* resp) void Executor::run() { auto config = std::shared_ptr(new ConnectionConfig()); - DEBUG("cmd=" << cmd << " args=" << args << " server=" << config->server); + //DEBUG("cmd=" << cmd << " args=" << args << " server=" << config->server); QString response = ""; try { char* resp = litelib_execute(this->cmd.toStdString().c_str(), this->args.toStdString().c_str()); @@ -461,7 +452,7 @@ Connection::Connection(MainWindow* m, std::shared_ptr conf) { this->config = conf; this->main = m; - qDebug() << __func__; + // qDebug() << __func__; // Register the JSON type as a type that can be passed between signals and slots. qRegisterMetaType("json"); } @@ -473,7 +464,7 @@ void Connection::doRPC(const QString cmd, const QString args, const std::functio return; } - DEBUG("cmd=" << cmd << " args=" << args); + //DEBUG("cmd=" << cmd << " args=" << args); // Create a runner. auto runner = new Executor(cmd, args); @@ -488,7 +479,7 @@ void Connection::doRPC(const QString cmd, const QString args, const std::functio void Connection::doRPCWithDefaultErrorHandling(const QString cmd, const QString args, const std::function& cb) { - DEBUG("cmd=" << cmd << " args=" << args); + //DEBUG("cmd=" << cmd << " args=" << args); doRPC(cmd, args, cb, [=] (QString err) { this->showTxError(err); }); @@ -496,7 +487,7 @@ void Connection::doRPCWithDefaultErrorHandling(const QString cmd, const QString void Connection::doRPCIgnoreError(const QString cmd, const QString args, const std::function& cb) { - DEBUG("cmd=" << cmd << " args=" << args); + // DEBUG("cmd=" << cmd << " args=" << args); doRPC(cmd, args, cb, [=] (auto) { // Ignored error handling }); @@ -504,7 +495,7 @@ void Connection::doRPCIgnoreError(const QString cmd, const QString args, const s void Connection::showTxError(const QString& error) { - qDebug() << __func__ << ": " << error; + // qDebug() << __func__ << ": " << error; if (error.isNull()) return; diff --git a/src/controller.cpp b/src/controller.cpp index e0dc505..6908fb4 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(); @@ -19,12 +22,12 @@ using json = nlohmann::json; Controller::Controller(MainWindow* main) { auto cl = new ConnectionLoader(main, this); - qDebug() << __func__ << ": cl=" << cl << endl; + //qDebug() << __func__ << ": cl=" << cl << endl; // Execute the load connection async, so we can set up the rest of RPC properly. QTimer::singleShot(1, [=]() { cl->loadConnection(); }); - qDebug() << __func__ << "after loadConnection" << endl; + // qDebug() << __func__ << "after loadConnection" << endl; this->main = main; this->ui = main->ui; @@ -122,6 +125,10 @@ void Controller::setConnection(Connection* c) ui->listChat->verticalScrollBar()->setValue( ui->listChat->verticalScrollBar()->maximum()); + + //fetch amounts of notes at startup + fetchAndProcessUnspentNotes(); + } // Build the RPC JSON Parameters for this tx @@ -133,8 +140,10 @@ void Controller::fillTxJsonParams(json& allRecepients, Tx tx) json rec = json::object(); //creating the JSON dust parameters in a std::vector to iterate over there during tx - std::vector dust(8); - dust.resize(8, json::object()); + std::vector dustTransactions(8); + for (auto& dust : dustTransactions) { + dust = json::object(); + } // Create Sietch zdust addr again to not use it twice. // Using DataStore singelton, to store the data outside of lambda, bing bada boom :D @@ -149,11 +158,20 @@ void Controller::fillTxJsonParams(json& allRecepients, Tx tx) // 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(); + dustTransactions.at(i)["address"] = DataStore::getSietchDataStore()->getData(QString("Sietch" + QString(i))).toStdString(); } DataStore::getSietchDataStore()->clear(); // clears the datastore + + // Only for Debugging/Testing: How many free Notes are available? + int spendableNotesCount = NoteCountDataStore::getInstance()->getSpendableNotesCount(); + QString addressWithMaxValue = NoteCountDataStore::getInstance()->getAddressWithMaxValue(); + + qDebug() << "Available notes over fee:" << spendableNotesCount; + // Clear NoteCountDataStore + DataStore::getNoteCountDataStore()->clear(); + const QString possibleCharacters("0123456789abcdef"); int sizerandomString = 512; const int randomStringLength = sizerandomString; @@ -168,19 +186,36 @@ void Controller::fillTxJsonParams(json& allRecepients, Tx tx) randomString.append(nextChar); } - dust.at(i)["memo"] = randomString.toStdString(); + dustTransactions.at(i)["memo"] = randomString.toStdString(); } + CAmount balanceAvailable = getModel()->getBalVerified(); + + // Create more Notes if spendableNotesCount < 30 and enough funds are available + if (spendableNotesCount < 30 && balanceAvailable.toDecimalString().toDouble() > (dustTransactions.size() * 0.0001)) { + // Create extra transaction + for (size_t i = 0; i < dustTransactions.size(); ++i) { + // Generate random memo + QString randomMemo; + for (int j = 0; j < randomStringLength; ++j) { + int index = QRandomGenerator::system()->bounded(0, possibleCharacters.length()); + randomMemo.append(possibleCharacters.at(index)); + } - for(auto &it: dust) - { - it["amount"] = 0; - } + dustTransactions.at(i)["address"] = addressWithMaxValue.toStdString(); + dustTransactions.at(i)["amount"] = 10000; + dustTransactions.at(i)["memo"] = randomMemo.toStdString(); + } + } else { + // Set amount for real Sietch transaction to 0 + for (auto &it : dustTransactions) { + 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]; + for (const auto& toAddr : tx.toAddrs) { + json rec = json::object(); rec["address"] = toAddr.addr.toStdString(); rec["amount"] = toAddr.amount.toqint64(); if (Settings::isZAddress(toAddr.addr) && !toAddr.memo.trimmed().isEmpty()) @@ -189,59 +224,21 @@ void Controller::fillTxJsonParams(json& allRecepients, Tx tx) allRecepients.push_back(rec); } - int decider = rand() % 100 + 1 ; ; // random int between 1 and 100 + int decider = rand() % 100 + 1; + int dustCount = (decider % 4 == 3) ? 5 : 6; 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) - }) ; - } + dustCount++; } - + for (int i = 0; i < dustCount; ++i) { + allRecepients.insert(allRecepients.begin(), dustTransactions.at(i)); + } } void Controller::noConnection() { - qDebug()<< __func__; + //qDebug()<< __func__; QIcon i = QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical); main->statusIcon->setPixmap(i.pixmap(16, 16)); main->statusIcon->setToolTip(""); @@ -274,7 +271,7 @@ void Controller::noConnection() /// This will refresh all the balance data from hushd void Controller::refresh(bool force) { - qDebug()<< __func__; + //qDebug()<< __func__; if (!zrpc->haveConnection()) return; @@ -301,7 +298,7 @@ void Controller::processInfo(const json& info) void Controller::getInfoThenRefresh(bool force) { - qDebug()<< __func__; + //qDebug()<< __func__; if (!zrpc->haveConnection()) return noConnection(); @@ -635,7 +632,7 @@ void Controller::setLag(int lag) void Controller::refreshAddresses() { - qDebug()<< __func__; + //qDebug()<< __func__; if (!zrpc->haveConnection()) return noConnection(); @@ -680,7 +677,7 @@ void Controller::updateUI(bool anyUnconfirmed) void Controller::supplyUpdate() { - qDebug()<< __func__ << ": updating supply"; + // qDebug()<< __func__ << ": updating supply"; // Get the total supply and render it with thousand decimal zrpc->fetchSupply([=] (const json& reply) { @@ -701,7 +698,7 @@ void Controller::supplyUpdate() { ui->supply_zaddr->setText("HUSH " +(QLocale(QLocale::English).toString(zfunds))); ui->supply_total->setText("HUSH " +(QLocale(QLocale::English).toString(total))); } - qDebug() << __func__ << ": supply=" << supply; + //qDebug() << __func__ << ": supply=" << supply; }); } @@ -890,7 +887,7 @@ void Controller::updateUIBalances() void Controller::refreshBalances() { - qDebug()<< __func__; + //qDebug()<< __func__; if (!zrpc->haveConnection()) return noConnection(); @@ -963,11 +960,11 @@ void printJsonValue(QTextStream& out, const nlohmann::json& j, int depth = 0) { void Controller::refreshTransactions() { - qDebug()<< __func__; + //qDebug()<< __func__; if (!zrpc->haveConnection()) return noConnection(); - qDebug() << __func__ << ": fetchTransactions"; + // qDebug() << __func__ << ": fetchTransactions"; zrpc->fetchTransactions([=] (json reply) { QList txdata; @@ -1079,7 +1076,7 @@ void Controller::refreshTransactions() { if (crypto_kx_seed_keypair(pk, sk, MESSAGEAS1) !=0) { main->logger->write("Keypair outgoing error"); - qDebug() << "refreshTransactions: crypto_kx_seed_keypair error"; + // qDebug() << "refreshTransactions: crypto_kx_seed_keypair error"; continue; } @@ -1090,7 +1087,7 @@ void Controller::refreshTransactions() { if (crypto_kx_server_session_keys(server_rx, server_tx, pk, sk, pubkeyBob) != 0) { main->logger->write("Suspicious client public outgoing key, bail out "); - qDebug() << "refreshTransactions: Suspicious client public outgoing key, aborting!"; + // qDebug() << "refreshTransactions: Suspicious client public outgoing key, aborting!"; continue; } @@ -1119,13 +1116,13 @@ void Controller::refreshTransactions() { if (crypto_secretstream_xchacha20poly1305_init_pull(&state, header, server_tx) != 0) { /* Invalid header, no need to go any further */ - qDebug() << "refreshTransactions: crypto_secretstream_xchacha20poly1305_init_pull error! Invalid header"; + // qDebug() << "refreshTransactions: crypto_secretstream_xchacha20poly1305_init_pull error! Invalid header"; continue; } if (crypto_secretstream_xchacha20poly1305_pull(&state, decrypted, NULL, tag, MESSAGE2, CIPHERTEXT1_LEN, NULL, 0) != 0) { /* Invalid/incomplete/corrupted ciphertext - abort */ - qDebug() << "refreshTransactions: crypto_secretstream_xchacha20poly1305_pull error! Invalid ciphertext"; + // qDebug() << "refreshTransactions: crypto_secretstream_xchacha20poly1305_pull error! Invalid ciphertext"; continue; } @@ -1155,7 +1152,7 @@ void Controller::refreshTransactions() { false ); - qDebug() << "refreshTransactions: adding chatItem with memodecrypt=" << memodecrypt; + // qDebug() << "refreshTransactions: adding chatItem with memodecrypt=" << memodecrypt; DataStore::getChatDataStore()->setData(ChatIDGenerator::getInstance()->generateID(item), item); // updateUIBalances(); } @@ -1269,8 +1266,8 @@ void Controller::refreshTransactions() { int position = it["position"].get(); int ciphercheck = memo.length() - crypto_secretstream_xchacha20poly1305_ABYTES; - qDebug() << __func__ << ": position=" << position << " headerbytes=" << headerbytes - << " ciphercheck=" << ciphercheck << " for memo=" << memo; + // qDebug() << __func__ << ": position=" << position << " headerbytes=" << headerbytes + // << " ciphercheck=" << ciphercheck << " for memo=" << memo; if ((memo.startsWith("{") == false) && (headerbytes > 0) && (ciphercheck > 0)) { @@ -1301,7 +1298,7 @@ void Controller::refreshTransactions() { if (crypto_kx_seed_keypair(pk, sk, MESSAGEAS1) !=0) { main->logger->write("Suspicious outgoing key pair, bail out "); - qDebug() << "refreshTransactions: (incoming) crypto_kx_seed_keypair error!"; + // qDebug() << "refreshTransactions: (incoming) crypto_kx_seed_keypair error!"; continue; } @@ -1312,7 +1309,7 @@ void Controller::refreshTransactions() { if (crypto_kx_client_session_keys(client_rx, client_tx, pk, sk, pubkeyBob) != 0) { main->logger->write("Suspicious client public incoming key, bail out "); - qDebug() << "refreshTransactions: (incoming) crypto_kx_client_session_keys error!"; + // qDebug() << "refreshTransactions: (incoming) crypto_kx_client_session_keys error!"; continue; } @@ -1340,13 +1337,13 @@ void Controller::refreshTransactions() { // crypto_secretstream_xchacha20poly1305_keygen(client_rx); if (crypto_secretstream_xchacha20poly1305_init_pull(&state, header, client_rx) != 0) { main->logger->write("Invalid header incoming, no need to go any further "); - qDebug() <<"refreshTransactions: (incoming) crypto_secretstream_xchacha20poly1305_init_pull error! memo=" << memo; + //qDebug() <<"refreshTransactions: (incoming) crypto_secretstream_xchacha20poly1305_init_pull error! memo=" << memo; continue; } if (crypto_secretstream_xchacha20poly1305_pull(&state, decrypted, NULL, tag, MESSAGE2, CIPHERTEXT1_LEN, NULL, 0) != 0) { main->logger->write("Invalid/incomplete/corrupted ciphertext - abort"); - qDebug() << "refreshTransactions: (incoming) crypto_secretstream_xchacha20poly1305_pull error! memo=" << memo; + // qDebug() << "refreshTransactions: (incoming) crypto_secretstream_xchacha20poly1305_pull error! memo=" << memo; continue; } @@ -1374,11 +1371,11 @@ void Controller::refreshTransactions() { ); auto iid = ChatIDGenerator::getInstance()->generateID(item); - qDebug() << "refreshTransactions: adding chatItem with item id=" << iid << " memodecrypt=" << memodecrypt; + // qDebug() << "refreshTransactions: adding chatItem with item id=" << iid << " memodecrypt=" << memodecrypt; DataStore::getChatDataStore()->setData(iid, item); } else { - qDebug() << __func__ << ": ignoring txid="<< txid; + // qDebug() << __func__ << ": ignoring txid="<< txid; } } else { @@ -1398,7 +1395,7 @@ void Controller::refreshTransactions() { isContact ); auto iid = ChatIDGenerator::getInstance()->generateID(item); - qDebug() << "refreshTransactions: adding chatItem for initial CR with item id="<< iid << " memo='" << memo << "'"; + // qDebug() << "refreshTransactions: adding chatItem for initial CR with item id="<< iid << " memo='" << memo << "'"; DataStore::getChatDataStore()->setData(iid, item); } } @@ -1425,7 +1422,7 @@ void Controller::refreshTransactions() { // Update model data, which updates the table view transactionsTableModel->replaceData(txdata); - qDebug() << __func__ << ": calling renderChatBox"; + // qDebug() << __func__ << ": calling renderChatBox"; chat->renderChatBox(ui, ui->listChat,ui->memoSizeChat); ui->listChat->verticalScrollBar()->setValue(ui->listChat->verticalScrollBar()->maximum()); @@ -1435,7 +1432,7 @@ void Controller::refreshTransactions() { void Controller::refreshChat(QListView *listWidget, QLabel *label) { - qDebug() << __func__ << ": calling renderChatBox"; + // qDebug() << __func__ << ": calling renderChatBox"; chat->renderChatBox(ui, listWidget, label); ui->listChat->verticalScrollBar()->setValue(ui->listChat->verticalScrollBar()->maximum()); @@ -1528,12 +1525,14 @@ void Controller::executeStandardUITransaction(Tx tx) ); } - // Execute a transaction! void Controller::executeTransaction(Tx tx, const std::function submitted, - const std::function error) + const std::function error) { +// Refresh the available unspent notes + fetchAndProcessUnspentNotes(); + unlockIfEncrypted([=] () { // First, create the json params json params = json::array(); @@ -1559,10 +1558,9 @@ void Controller::executeTransaction(Tx tx, }); } - void Controller::checkForUpdate(bool silent) { - qDebug()<< __func__; + // qDebug()<< __func__; // No checking for updates, needs testing with Gitea return; if (!zrpc->haveConnection()) @@ -1653,7 +1651,7 @@ void Controller::checkForUpdate(bool silent) // Get the hush->USD price from coinmarketcap using their API void Controller::refreshHUSHPrice() { - qDebug()<< __func__; + // qDebug()<< __func__; if (!zrpc->haveConnection()) return; @@ -2009,7 +2007,7 @@ void Controller::shutdownhushd() // Save the wallet and exit the lightclient library cleanly. if (!zrpc) { zrpc = new LiteInterface(); - qDebug() << __func__ << ": created new rpc connection zrpc=" << zrpc; + // qDebug() << __func__ << ": created new rpc connection zrpc=" << zrpc; } if (zrpc && zrpc->haveConnection()) @@ -2076,3 +2074,42 @@ QString Controller::getDefaultTAddress() return QString(); } + +void Controller::fetchAndProcessUnspentNotes() { + zrpc->fetchUnspent([=] (json reply) { + + if (reply.find("unspent_notes") == reply.end() || !reply["unspent_notes"].is_array()) { + qDebug() << "Fehler: 'unspent_notes' fehlt oder ist kein Array"; + return; + } + + int spendableNotesCount = 0; + std::map addressValues; + std::string addressWithMaxValue; + int maxValue = 0; + + 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()) { + + 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; + } + } + } + + NoteCountDataStore::getInstance()->setSpendableNotesCount(spendableNotesCount); + + if (!addressWithMaxValue.empty()) { + NoteCountDataStore::getInstance()->setAddressWithMaxValue(QString::fromStdString(addressWithMaxValue), maxValue); + } + }); +} diff --git a/src/controller.h b/src/controller.h index a079bec..debc699 100644 --- a/src/controller.h +++ b/src/controller.h @@ -98,6 +98,8 @@ public: void noConnection(); bool isEmbedded() { return ehushd != nullptr; } + void fetchAndProcessUnspentNotes(); + void encryptWallet(QString password, const std::function& cb) { zrpc->encryptWallet(password, cb); } diff --git a/src/firsttimewizard.cpp b/src/firsttimewizard.cpp index daa272e..45fdf46 100644 --- a/src/firsttimewizard.cpp +++ b/src/firsttimewizard.cpp @@ -725,42 +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 { QString reply = ""; diff --git a/src/liteinterface.cpp b/src/liteinterface.cpp index 03c206d..c7473b6 100644 --- a/src/liteinterface.cpp +++ b/src/liteinterface.cpp @@ -45,12 +45,15 @@ void LiteInterface::importTPrivKey(QString addr,const std::function& void LiteInterface::fetchUnspent(const std::function& cb) { - if (conn == nullptr) + if (conn == nullptr) { + qDebug() << "fetchUnspent: conn ist nullptr, breche ab"; return; + } conn->doRPCWithDefaultErrorHandling("notes", "", cb); } + void LiteInterface::createNewZaddr(bool, const std::function& cb) { if (conn == nullptr) return; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 234bbca..8137b60 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -61,7 +61,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { - qDebug() << __func__ << endl; + // qDebug() << __func__ << endl; // Include css QString theme_name; @@ -427,7 +427,7 @@ void MainWindow::closeEvent(QCloseEvent* event) { void MainWindow::closeEventpw(QCloseEvent* event) { // Let the RPC know to shut down any running service. - qDebug() << __func__ << ": event=" << event << " this=" << this; + // qDebug() << __func__ << ": event=" << event << " this=" << this; if (rpc) { rpc->shutdownhushd(); } else { @@ -742,7 +742,7 @@ void MainWindow::setMoneyMemo(QString moneymemo) } void MainWindow::setupStatusBar() { - qDebug() << __func__ << endl; + // qDebug() << __func__ << endl; // Status Bar loadingLabel = new QLabel(); loadingMovie = new QMovie(":/icons/res/loading.gif"); diff --git a/src/version.h b/src/version.h index 928b60b..67c2064 100644 --- a/src/version.h +++ b/src/version.h @@ -1,3 +1 @@ -// Copyright 2019-2024 The Hush developers -// Released under the GPLv3 #define APP_VERSION "2.0.1"