Merge pull request #8 from DenioD/dev

switch to Hush unit
This commit is contained in:
Denio
2019-10-26 00:03:21 +02:00
committed by GitHub
46 changed files with 5697 additions and 4232 deletions
+2 -2
View File
@@ -18,10 +18,10 @@ script:
- qmake -v
- clang++ -v
- g++-8 -v
- qmake hush-qt-wallet.pro CONFIG+=release -spec linux-clang
- qmake silentdragon-lite.pro CONFIG+=release -spec linux-clang
- make CC=clang CXX=clang++ -j2
- make distclean
- qmake hush-qt-wallet.pro CONFIG+=release -spec linux-g++
- qmake silentdragon-lite.pro CONFIG+=release -spec linux-g++
- res/libsodium/buildlibsodium.sh
- make CC=gcc-8 CXX=g++-8 -j2
+1
View File
@@ -0,0 +1 @@
[{"excluded":[],"includePaths":["/home/denio/silentdragon-lite/src/3rdparty","/home/denio/silentdragon-lite/src","/home/denio/silentdragon-lite/singleapplication","/home/denio/silentdragon-lite/res","/home/denio/Qt5.13.1/5.13.1/gcc_64/include","/home/denio/Qt5.13.1/5.13.1/gcc_64/include/QtWidgets","/home/denio/Qt5.13.1/5.13.1/gcc_64/include/QtGui","/home/denio/Qt5.13.1/5.13.1/gcc_64/include/QtWebSockets","/home/denio/Qt5.13.1/5.13.1/gcc_64/include/QtNetwork","/home/denio/Qt5.13.1/5.13.1/gcc_64/include/QtCore","/home/denio/silentdragon-lite/bin","/usr/include/libdrm","/home/denio/silentdragon-lite/src"],"projectFile":"/home/denio/silentdragon-lite/silentdragon-lite.pro","sources":["/home/denio/silentdragon-lite/lib/silentdragonlitelib.h","/home/denio/silentdragon-lite/singleapplication/singleapplication.cpp","/home/denio/silentdragon-lite/singleapplication/singleapplication.h","/home/denio/silentdragon-lite/singleapplication/singleapplication_p.cpp","/home/denio/silentdragon-lite/singleapplication/singleapplication_p.h","/home/denio/silentdragon-lite/src/3rdparty/json/json.hpp","/home/denio/silentdragon-lite/src/3rdparty/qrcode/BitBuffer.cpp","/home/denio/silentdragon-lite/src/3rdparty/qrcode/BitBuffer.hpp","/home/denio/silentdragon-lite/src/3rdparty/qrcode/QrCode.cpp","/home/denio/silentdragon-lite/src/3rdparty/qrcode/QrCode.hpp","/home/denio/silentdragon-lite/src/3rdparty/qrcode/QrSegment.cpp","/home/denio/silentdragon-lite/src/3rdparty/qrcode/QrSegment.hpp","/home/denio/silentdragon-lite/src/about.ui","/home/denio/silentdragon-lite/src/addressbook.cpp","/home/denio/silentdragon-lite/src/addressbook.h","/home/denio/silentdragon-lite/src/addressbook.ui","/home/denio/silentdragon-lite/src/addresscombo.cpp","/home/denio/silentdragon-lite/src/addresscombo.h","/home/denio/silentdragon-lite/src/balancestablemodel.cpp","/home/denio/silentdragon-lite/src/balancestablemodel.h","/home/denio/silentdragon-lite/src/confirm.ui","/home/denio/silentdragon-lite/src/connection.cpp","/home/denio/silentdragon-lite/src/connection.h","/home/denio/silentdragon-lite/src/connection.ui","/home/denio/silentdragon-lite/src/controller.cpp","/home/denio/silentdragon-lite/src/controller.h","/home/denio/silentdragon-lite/src/createhushconfdialog.ui","/home/denio/silentdragon-lite/src/datamodel.cpp","/home/denio/silentdragon-lite/src/datamodel.h","/home/denio/silentdragon-lite/src/fillediconlabel.cpp","/home/denio/silentdragon-lite/src/fillediconlabel.h","/home/denio/silentdragon-lite/src/liteinterface.cpp","/home/denio/silentdragon-lite/src/liteinterface.h","/home/denio/silentdragon-lite/src/logger.cpp","/home/denio/silentdragon-lite/src/logger.h","/home/denio/silentdragon-lite/src/main.cpp","/home/denio/silentdragon-lite/src/mainwindow.cpp","/home/denio/silentdragon-lite/src/mainwindow.h","/home/denio/silentdragon-lite/src/mainwindow.ui","/home/denio/silentdragon-lite/src/memodialog.ui","/home/denio/silentdragon-lite/src/memoedit.cpp","/home/denio/silentdragon-lite/src/memoedit.h","/home/denio/silentdragon-lite/src/migration.ui","/home/denio/silentdragon-lite/src/mobileappconnector.cpp","/home/denio/silentdragon-lite/src/mobileappconnector.h","/home/denio/silentdragon-lite/src/mobileappconnector.ui","/home/denio/silentdragon-lite/src/newrecurring.ui","/home/denio/silentdragon-lite/src/precompiled.h","/home/denio/silentdragon-lite/src/privkey.ui","/home/denio/silentdragon-lite/src/qrcodelabel.cpp","/home/denio/silentdragon-lite/src/qrcodelabel.h","/home/denio/silentdragon-lite/src/recurring.cpp","/home/denio/silentdragon-lite/src/recurring.h","/home/denio/silentdragon-lite/src/recurringdialog.ui","/home/denio/silentdragon-lite/src/recurringmultiple.ui","/home/denio/silentdragon-lite/src/recurringpayments.ui","/home/denio/silentdragon-lite/src/requestdialog.cpp","/home/denio/silentdragon-lite/src/requestdialog.h","/home/denio/silentdragon-lite/src/requestdialog.ui","/home/denio/silentdragon-lite/src/sendtab.cpp","/home/denio/silentdragon-lite/src/settings.cpp","/home/denio/silentdragon-lite/src/settings.h","/home/denio/silentdragon-lite/src/settings.ui","/home/denio/silentdragon-lite/src/txtablemodel.cpp","/home/denio/silentdragon-lite/src/txtablemodel.h","/home/denio/silentdragon-lite/src/viewalladdresses.cpp","/home/denio/silentdragon-lite/src/viewalladdresses.h","/home/denio/silentdragon-lite/src/viewalladdresses.ui","/home/denio/silentdragon-lite/src/websockets.cpp","/home/denio/silentdragon-lite/src/websockets.h"],"translations":["/home/denio/silentdragon-lite/res/zec_qt_wallet_es.ts","/home/denio/silentdragon-lite/res/zec_qt_wallet_fr.ts","/home/denio/silentdragon-lite/res/zec_qt_wallet_de.ts","/home/denio/silentdragon-lite/res/zec_qt_wallet_pt.ts","/home/denio/silentdragon-lite/res/zec_qt_wallet_it.ts","/home/denio/silentdragon-lite/res/zec_qt_wallet_zh.ts","/home/denio/silentdragon-lite/res/zec_qt_wallet_tr.ts","/home/denio/silentdragon-lite/res/zec_qt_wallet_template.ts"]}]
+1 -6
View File
@@ -13,12 +13,7 @@
<file>res/logobig.gif</file>
</qresource>
<qresource prefix="/translations">
<file>res/zec_qt_wallet_es.qm</file>
<file>res/zec_qt_wallet_fr.qm</file>
<file>res/zec_qt_wallet_pt.qm</file>
<file>res/zec_qt_wallet_it.qm</file>
<file>res/zec_qt_wallet_zh.qm</file>
<file>res/zec_qt_wallet_tr.qm</file>
<file>res/zec_qt_wallet_de.qm</file>
</qresource>
<qresource prefix="/css">
<file>res/css/blue.css</file>
+3 -3
View File
@@ -1051,7 +1051,7 @@ version = "0.1.0"
dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
"silentdragonlitelib 0.1.0 (git+https://github.com/DenioD/silentdragonlite-cli?rev=a9d235e117da1fdbe3c576d0713b87cfdf97baf6)",
"silentdragonlitelib 0.1.0 (git+https://github.com/DenioD/silentdragonlite-cli?rev=11d5d15e8b03c0a5b6eae1af00ac17fb7660a004)",
]
[[package]]
@@ -1467,7 +1467,7 @@ dependencies = [
[[package]]
name = "silentdragonlitelib"
version = "0.1.0"
source = "git+https://github.com/DenioD/silentdragonlite-cli?rev=a9d235e117da1fdbe3c576d0713b87cfdf97baf6#a9d235e117da1fdbe3c576d0713b87cfdf97baf6"
source = "git+https://github.com/DenioD/silentdragonlite-cli?rev=11d5d15e8b03c0a5b6eae1af00ac17fb7660a004#11d5d15e8b03c0a5b6eae1af00ac17fb7660a004"
dependencies = [
"base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bellman 0.1.0 (git+https://github.com/DenioD/librustzcash.git?rev=caaee693c47c2ee9ecd1e1546b8fe3c714f342bc)",
@@ -2481,7 +2481,7 @@ dependencies = [
"checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2"
"checksum serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)" = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35"
"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d"
"checksum silentdragonlitelib 0.1.0 (git+https://github.com/DenioD/silentdragonlite-cli?rev=a9d235e117da1fdbe3c576d0713b87cfdf97baf6)" = "<none>"
"checksum silentdragonlitelib 0.1.0 (git+https://github.com/DenioD/silentdragonlite-cli?rev=11d5d15e8b03c0a5b6eae1af00ac17fb7660a004)" = "<none>"
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7"
"checksum sodiumoxide 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585232e78a4fc18133eef9946d3080befdf68b906c51b621531c37e91787fa2b"
+1 -1
View File
@@ -11,4 +11,4 @@ crate-type = ["staticlib"]
[dependencies]
libc = "0.2.58"
lazy_static = "1.4.0"
silentdragonlitelib = { git = "https://github.com/DenioD/silentdragonlite-cli", rev = "a9d235e117da1fdbe3c576d0713b87cfdf97baf6" }
silentdragonlitelib = { git = "https://github.com/DenioD/silentdragonlite-cli", rev = "11d5d15e8b03c0a5b6eae1af00ac17fb7660a004" }
+12 -4
View File
@@ -5,13 +5,21 @@
extern "C" {
#endif
extern bool litelib_wallet_exists (const char* chain_name, const char* dir);
extern char * litelib_initialze_existing (bool dangerous, const char* server);
extern char * litelib_execute (const char* s, const char* args);
extern void litelib_rust_free_string (char* s);
extern bool litelib_wallet_exists (const char* chain_name);
extern char * litelib_initialize_new (bool dangerous, const char* server);
extern char * litelib_initialize_new_from_phrase
(bool dangerous, const char* server, const char* seed,
unsigned long long birthday);
extern char * litelib_initialize_existing (bool dangerous, const char* server);
extern char * litelib_execute (const char* s, const char* args);
extern void litelib_rust_free_string (char* s);
#ifdef __cplusplus
}
#endif
// This is a function implemented in connection.cpp that will process a string response from
// the litelib and turn into into a QString in a memory-safe way.
QString litelib_process_response(char* resp);
#endif
+120 -17
View File
@@ -4,7 +4,7 @@ extern crate lazy_static;
use libc::{c_char};
use std::ffi::{CStr, CString};
use std::sync::{Mutex};
use std::sync::{Mutex, Arc};
use std::cell::RefCell;
use silentdragonlitelib::{commands, lightclient::{LightClient, LightClientConfig}};
@@ -13,32 +13,130 @@ use silentdragonlitelib::{commands, lightclient::{LightClient, LightClientConfig
// so we don't have to keep creating it. We need to store it here, in rust
// because we can't return such a complex structure back to C++
lazy_static! {
static ref LIGHTCLIENT: Mutex<RefCell<Option<LightClient>>> = Mutex::new(RefCell::new(None));
static ref LIGHTCLIENT: Mutex<RefCell<Option<Arc<LightClient>>>> = Mutex::new(RefCell::new(None));
}
// Check if there is an existing wallet
// Initialize a new lightclient and store its value
#[no_mangle]
pub extern fn litelib_initialze_existing(dangerous: bool, server: *const c_char) -> *mut c_char {
pub extern fn litelib_wallet_exists(chain_name: *const c_char) -> bool {
let chain_name_str = unsafe {
assert!(!chain_name.is_null());
CStr::from_ptr(chain_name).to_string_lossy().into_owned()
};
let config = LightClientConfig::create_unconnected(chain_name_str, None);
println!("Wallet exists: {}", config.wallet_exists());
config.wallet_exists()
}
/// Create a new wallet and return the seed for the newly created wallet.
#[no_mangle]
pub extern fn litelib_initialize_new(dangerous: bool, server: *const c_char) -> *mut c_char {
let server_str = unsafe {
assert!(!server.is_null());
CStr::from_ptr(server).to_string_lossy().into_owned()
};
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),
Err(e) => {
let e_str = CString::new(format!("Error: {}", e)).unwrap();
return e_str.into_raw();
}
};
let lightclient = match LightClient::new(&config, latest_block_height) {
Ok(l) => l,
Err(e) => {
let e_str = CString::new(format!("Error: {}", e)).unwrap();
return e_str.into_raw();
}
};
let seed = match lightclient.do_seed_phrase() {
Ok(s) => s.dump(),
Err(e) => {
let e_str = CString::new(format!("Error: {}", e)).unwrap();
return e_str.into_raw();
}
};
LIGHTCLIENT.lock().unwrap().replace(Some(Arc::new(lightclient)));
// Return the wallet's seed
let s_str = CString::new(seed).unwrap();
return s_str.into_raw();
}
/// Restore a wallet from the seed phrase
#[no_mangle]
pub extern fn litelib_initialize_new_from_phrase(dangerous: bool, server: *const c_char,
seed: *const c_char, birthday: u64) -> *mut c_char {
let server_str = unsafe {
assert!(!server.is_null());
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()
};
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),
Err(e) => {
let e_str = CString::new(format!("Error: {}", e)).unwrap();
return e_str.into_raw();
}
}
};
let lightclient = match LightClient::new_from_phrase(seed_str, &config, birthday) {
Ok(l) => l,
Err(e) => {
let e_str = CString::new(format!("Error: {}", e)).unwrap();
return e_str.into_raw();
}
};
let seed = match lightclient.do_seed_phrase() {
Ok(s) => s.dump(),
Err(e) => {
let e_str = CString::new(format!("Error: {}", e)).unwrap();
return e_str.into_raw();
}
};
LIGHTCLIENT.lock().unwrap().replace(Some(Arc::new(lightclient)));
let c_str = CString::new("OK").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 {
let server_str = unsafe {
assert!(!server.is_null());
CStr::from_ptr(server).to_string_lossy().into_owned()
};
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),
Err(e) => {
let e_str = CString::new(format!("Error: {}", e)).unwrap();
return e_str.into_raw();
}
};
let lightclient = match LightClient::read_from_disk(&config) {
Ok(l) => l,
Err(e) => {
@@ -47,7 +145,7 @@ pub extern fn litelib_initialze_existing(dangerous: bool, server: *const c_char)
}
};
LIGHTCLIENT.lock().unwrap().replace(Some(lightclient));
LIGHTCLIENT.lock().unwrap().replace(Some(Arc::new(lightclient)));
let c_str = CString::new("OK").unwrap();
return c_str.into_raw();
@@ -69,16 +167,21 @@ pub extern fn litelib_execute(cmd: *const c_char, args: *const c_char) -> *mut c
let resp: String;
{
let lc = LIGHTCLIENT.lock().unwrap();
let lightclient: Arc<LightClient>;
{
let lc = LIGHTCLIENT.lock().unwrap();
if lc.borrow().is_none() {
let e_str = CString::new("Error: Light Client is not initialized").unwrap();
return e_str.into_raw();
}
if lc.borrow().is_none() {
let e_str = CString::new("Error: Light Client is not initialized").unwrap();
return e_str.into_raw();
}
lightclient = lc.borrow().as_ref().unwrap().clone();
};
let args = if arg_str.is_empty() { vec![] } else { vec![arg_str.as_ref()] };
resp = commands::do_user_command(&cmd_str, &args, lc.borrow().as_ref().unwrap()).clone();
resp = commands::do_user_command(&cmd_str, &args, lightclient.as_ref()).clone();
};
let c_str = CString::new(resp.as_bytes()).unwrap();
Binary file not shown.
+537 -1003
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.
+557 -1039
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.
+316 -397
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.
+314 -415
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.
+311 -412
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.
+5 -5
View File
@@ -215,7 +215,7 @@
</message>
<message>
<location filename="../src/mainwindow.ui" line="864"/>
<source>You are currently not mining</source>
<source>This is a Lightwallet, you cant mine with it! not mining</source>
<translation type="unfinished">YOUR_TRANSLATION_HERE</translation>
</message>
<message>
@@ -228,17 +228,17 @@
</message>
<message>
<location filename="../src/mainwindow.ui" line="891"/>
<source>Block height</source>
<source>Blockheight</source>
<translation type="unfinished">YOUR_TRANSLATION_HERE</translation>
</message>
<message>
<location filename="../src/mainwindow.ui" line="905"/>
<source>Network solution rate</source>
<source>Version hushd light rate</source>
<translation type="unfinished">YOUR_TRANSLATION_HERE</translation>
</message>
<message>
<location filename="../src/mainwindow.ui" line="912"/>
<source>Connections</source>
<source>Vendor</source>
<translation type="unfinished">YOUR_TRANSLATION_HERE</translation>
</message>
<message>
@@ -659,7 +659,7 @@ Not starting embedded hushd because --no-embedded was passed</source>
</message>
<message>
<location filename="../src/rpc.cpp" line="578"/>
<source>Block height</source>
<source>Blockheight</source>
<translation type="unfinished">YOUR_TRANSLATION_HERE</translation>
</message>
<message>
Binary file not shown.
+334 -346
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.
+326 -369
View File
File diff suppressed because it is too large Load Diff
+6
View File
@@ -36,6 +36,7 @@ UI_DIR = src
CONFIG += c++14
SOURCES += \
src/firsttimewizard.cpp \
src/main.cpp \
src/mainwindow.cpp \
src/balancestablemodel.cpp \
@@ -62,6 +63,7 @@ SOURCES += \
src/liteinterface.cpp
HEADERS += \
src/firsttimewizard.h \
src/mainwindow.h \
src/precompiled.h \
src/balancestablemodel.h \
@@ -91,7 +93,10 @@ HEADERS += \
FORMS += \
src/mainwindow.ui \
src/migration.ui \
src/newseed.ui \
src/newwallet.ui \
src/recurringpayments.ui \
src/restoreseed.ui \
src/settings.ui \
src/about.ui \
src/confirm.ui \
@@ -115,6 +120,7 @@ TRANSLATIONS = res/zec_qt_wallet_es.ts \
res/zec_qt_wallet_it.ts \
res/zec_qt_wallet_zh.ts \
res/zec_qt_wallet_tr.ts
include(singleapplication/singleapplication.pri)
DEFINES += QAPPLICATION_CLASS=QApplication
BIN
View File
Binary file not shown.
+3 -4
View File
@@ -2,12 +2,11 @@
#include "addressbook.h"
#include "settings.h"
BalancesTableModel::BalancesTableModel(QObject *parent)
: QAbstractTableModel(parent) {
}
void BalancesTableModel::setNewData(const QMap<QString, qint64> balances,
void BalancesTableModel::setNewData(const QMap<QString, double> balances,
const QList<UnspentOutput> outputs)
{
loading = false;
@@ -22,7 +21,7 @@ void BalancesTableModel::setNewData(const QMap<QString, qint64> balances,
// Process the address balances into a list
delete modeldata;
modeldata = new QList<std::tuple<QString, qint64>>();
modeldata = new QList<std::tuple<QString, double>>();
std::for_each(balances.keyBegin(), balances.keyEnd(), [=] (auto keyIt) {
if (balances.value(keyIt) > 0)
modeldata->push_back(std::make_tuple(keyIt, balances.value(keyIt)));
@@ -95,7 +94,7 @@ QVariant BalancesTableModel::data(const QModelIndex &index, int role) const
if(role == Qt::ToolTipRole) {
switch (index.column()) {
case 0: return AddressBook::addLabelToAddress(std::get<0>(modeldata->at(index.row())));
case 1: return Settings::getUSDFromhushAmount(std::get<1>(modeldata->at(index.row())));
case 1: return Settings::getUSDFormat(std::get<1>(modeldata->at(index.row())));
}
}
+3 -2
View File
@@ -4,13 +4,14 @@
#include "precompiled.h"
#include "datamodel.h"
class BalancesTableModel : public QAbstractTableModel
{
public:
BalancesTableModel(QObject* parent);
~BalancesTableModel();
void setNewData(const QMap<QString, qint64> balances, const QList<UnspentOutput> outputs);
void setNewData(const QMap<QString, double> balances, const QList<UnspentOutput> outputs);
int rowCount(const QModelIndex &parent) const;
int columnCount(const QModelIndex &parent) const;
@@ -18,7 +19,7 @@ public:
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
private:
QList<std::tuple<QString, qint64>>* modeldata = nullptr;
QList<std::tuple<QString, double>>* modeldata = nullptr;
QList<UnspentOutput>* utxos = nullptr;
bool loading = true;
+82 -33
View File
@@ -2,9 +2,11 @@
#include "mainwindow.h"
#include "settings.h"
#include "ui_connection.h"
#include "firsttimewizard.h"
#include "ui_createhushconfdialog.h"
#include "controller.h"
#include "../lib/silentdragonlitelib.h"
#include "precompiled.h"
@@ -20,9 +22,12 @@ ConnectionLoader::ConnectionLoader(MainWindow* main, Controller* rpc) {
connD->setupUi(d);
QPixmap logo(":/img/res/logobig.gif");
connD->topIcon->setBasePixmap(logo.scaled(256, 256, Qt::KeepAspectRatio, Qt::SmoothTransformation));
isSyncing = new QAtomicInteger<bool>();
}
ConnectionLoader::~ConnectionLoader() {
ConnectionLoader::~ConnectionLoader() {
delete isSyncing;
delete connD;
delete d;
}
@@ -42,19 +47,77 @@ void ConnectionLoader::doAutoConnect() {
// Initialize the library
main->logger->write(QObject::tr("Attempting to initialize"));
litelib_initialze_existing(config->dangerous, config->server.toStdString().c_str());
// Check to see if there's an existing wallet
if (litelib_wallet_exists(Settings::getChainName().toStdString().c_str())) {
main->logger->write(QObject::tr("Using existing wallet."));
litelib_initialize_existing(config->dangerous, config->server.toStdString().c_str());
} else {
main->logger->write(QObject::tr("Create/restore wallet."));
litelib_initialize_existing(config->dangerous, config->server.toStdString().c_str());
d->show();
}
auto connection = makeConnection(config);
// After the lib is initialized, try to do get info
connection->doRPC("info", "", [=](auto reply) {
// If success, set the connection
// If success, set the connection
main->logger->write("Connection is online.");
this->doRPCSetConnection(connection);
}, [=](auto err) {});
isSyncing = new QAtomicInteger<bool>();
isSyncing->store(true);
// Do a sync at startup
syncTimer = new QTimer(main);
connection->doRPCWithDefaultErrorHandling("sync", "", [=](auto) {
isSyncing->store(false);
// Cancel the timer
syncTimer->deleteLater();
// When sync is done, set the connection
this->doRPCSetConnection(connection);
});
// While it is syncing, we'll show the status updates while it is alive.
QObject::connect(syncTimer, &QTimer::timeout, [=]() {
// Check the sync status
if (isSyncing != nullptr && isSyncing->load()) {
// Get the sync status
connection->doRPC("syncstatus", "", [=](json reply) {
if (isSyncing != nullptr && reply.find("synced_blocks") != reply.end()) {
qint64 synced = reply["synced_blocks"].get<json::number_unsigned_t>();
qint64 total = reply["total_blocks"].get<json::number_unsigned_t>();
showInformation("Synced " + QString::number(synced) + " / " + QString::number(total));
}
},
[=](QString err) {
qDebug() << "Sync error" << err;
});
}
});
syncTimer->setInterval(1* 1000);
syncTimer->start();
}, [=](QString err) {
showError(err);
});
}
void ConnectionLoader::createOrRestore(bool dangerous, QString server) {
// Close the startup dialog, since we'll be showing the wizard
d->hide();
// Create a wizard
FirstTimeWizard wizard(dangerous, server);
wizard.exec();
}
void ConnectionLoader::doRPCSetConnection(Connection* conn) {
qDebug() << "Connectionloader finished, setting connection";
rpc->setConnection(conn);
d->accept();
@@ -68,20 +131,9 @@ Connection* ConnectionLoader::makeConnection(std::shared_ptr<ConnectionConfig> c
// Update the UI with the status
void ConnectionLoader::showInformation(QString info, QString detail) {
static int rescanCount = 0;
if (detail.toLower().startsWith("rescan")) {
rescanCount++;
}
if (rescanCount > 10) {
detail = detail + "\n" + QObject::tr("This may take several hours");
}
qDebug() << "Showing info " << info << ":" << detail;
connD->status->setText(info);
connD->statusDetail->setText(detail);
if (rescanCount < 10)
main->logger->write(info + ":" + detail);
}
/**
@@ -94,15 +146,7 @@ void ConnectionLoader::showError(QString explanation) {
d->close();
}
/***********************************************************************************
* Connection, Executor and Callback Class
************************************************************************************/
void Executor::run() {
char* resp = litelib_execute(this->cmd.toStdString().c_str(), this->args.toStdString().c_str());
// Copy the string, since we need to return this back to rust
QString litelib_process_response(char* resp) {
char* resp_copy = new char[strlen(resp) + 1];
strcpy(resp_copy, resp);
litelib_rust_free_string(resp);
@@ -111,6 +155,17 @@ void Executor::run() {
memset(resp_copy, '-', strlen(resp_copy));
delete[] resp_copy;
return reply;
}
/***********************************************************************************
* Connection, Executor and Callback Class
************************************************************************************/
void Executor::run() {
char* resp = litelib_execute(this->cmd.toStdString().c_str(), this->args.toStdString().c_str());
QString reply = litelib_process_response(resp);
qDebug() << "Reply=" << reply;
auto parsed = json::parse(reply.toStdString().c_str(), nullptr, false);
if (parsed.is_discarded() || parsed.is_null()) {
@@ -126,8 +181,6 @@ void Executor::run() {
void Callback::processRPCCallback(json resp) {
const bool isGuiThread = QThread::currentThread() == QCoreApplication::instance()->thread();
qDebug() << "Doing RPC callback: isGUI=" << isGuiThread;
this->cb(resp);
// Destroy self
@@ -135,8 +188,6 @@ void Callback::processRPCCallback(json resp) {
}
void Callback::processError(QString resp) {
const bool isGuiThread = QThread::currentThread() == QCoreApplication::instance()->thread();
qDebug() << "Doing RPC callback: isGUI=" << isGuiThread;
this->errCb(resp);
// Destroy self
@@ -158,9 +209,7 @@ void Connection::doRPC(const QString cmd, const QString args, const std::functio
return;
}
const bool isGuiThread =
QThread::currentThread() == QCoreApplication::instance()->thread();
qDebug() << "Doing RPC: isGUI=" << isGuiThread;
qDebug() << "Doing RPC: " << cmd;
// Create a runner.
auto runner = new Executor(cmd, args);
+9 -4
View File
@@ -33,16 +33,21 @@ private:
void doAutoConnect();
void createOrRestore(bool dangerous, QString server);
void showError(QString explanation);
void showInformation(QString info, QString detail = "");
void doRPCSetConnection(Connection* conn);
QDialog* d;
Ui_ConnectionDialog* connD;
QTimer* syncTimer = nullptr;
QAtomicInteger<bool>* isSyncing = nullptr;
MainWindow* main;
Controller* rpc;
QDialog* d = nullptr;
Ui_ConnectionDialog* connD = nullptr;
MainWindow* main = nullptr;
Controller* rpc = nullptr;
};
/**
+73 -146
View File
@@ -64,7 +64,7 @@ void Controller::setConnection(Connection* c) {
this->zrpc->setConnection(c);
ui->statusBar->showMessage("Ready!");
ui->statusBar->showMessage("Your hushd is connected");
// See if we need to remove the reindex/rescan flags from the hush.conf file
auto hushConfLocation = Settings::getInstance()->gethushdConfLocation();
@@ -96,7 +96,7 @@ void Controller::fillTxJsonParams(json& allRecepients, Tx tx) {
// Construct the JSON params
json rec = json::object();
rec["address"] = toAddr.addr.toStdString();
rec["amount"] = toAddr.amount;
rec["amount"] = toAddr.amount * 10000000;
if (Settings::isZAddress(toAddr.addr) && !toAddr.memo.trimmed().isEmpty())
rec["memo"] = toAddr.memo.toStdString();
@@ -120,7 +120,7 @@ void Controller::noConnection() {
main->ui->statusBar->showMessage(QObject::tr("No Connection"), 1000);
// Clear balances table.
QMap<QString, qint64> emptyBalances;
QMap<QString, double> emptyBalances;
QList<UnspentOutput> emptyOutputs;
balancesTableModel->setNewData(emptyBalances, emptyOutputs);
@@ -161,21 +161,25 @@ void Controller::getInfoThenRefresh(bool force) {
prevCallSucceeded = true;
// Testnet?
QString chainName;
if (!reply["chain_name"].is_null()) {
Settings::getInstance()->setTestnet(reply["chain_name"].get<json::string_t>() == "test");
chainName = QString::fromStdString(reply["chain_name"].get<json::string_t>());
Settings::getInstance()->setTestnet(chainName == "test");
};
// Recurring pamynets are testnet only
if (!Settings::getInstance()->isTestnet())
main->disableRecurring();
// Connected, so display checkmark.
QIcon i(":/icons/res/connected.gif");
main->statusIcon->setPixmap(i.pixmap(16, 16));
static int lastBlock = 0;
int curBlock = reply["latest_block_height"].get<json::number_integer_t>();
model->setLatestBlock(curBlock);
// Connected, so display checkmark.
QIcon i(":/icons/res/connected.gif");
main->statusLabel->setText(chainName + "(" + QString::number(curBlock) + ")");
main->statusIcon->setPixmap(i.pixmap(16, 16));
//int version = reply["version"].get<json::string_t>();
int version = 1;
Settings::getInstance()->sethushdVersion(version);
@@ -251,7 +255,7 @@ void Controller::updateUI(bool anyUnconfirmed) {
};
// Function to process reply of the listunspent and z_listunspent API calls, used below.
bool Controller::processUnspent(const json& reply, QMap<QString, qint64>* balancesMap, QList<UnspentOutput>* newUtxos) {
bool Controller::processUnspent(const json& reply, QMap<QString, double>* balancesMap, QList<UnspentOutput>* newUtxos) {
bool anyUnconfirmed = false;
auto processFn = [=](const json& array) {
@@ -259,11 +263,11 @@ bool Controller::processUnspent(const json& reply, QMap<QString, qint64>* balanc
QString qsAddr = QString::fromStdString(it["address"]);
int block = it["created_in_block"].get<json::number_unsigned_t>();
QString txid = QString::fromStdString(it["created_in_txid"]);
QString amount = Settings::getDecimalString(it["value"].get<json::number_unsigned_t>());
QString amount = Settings::getDecimalString(it["value"].get<json::number_float_t>());
newUtxos->push_back(UnspentOutput{ qsAddr, txid, amount, block, true });
(*balancesMap)[qsAddr] = (*balancesMap)[qsAddr] + it["value"].get<json::number_unsigned_t>();
(*balancesMap)[qsAddr] = ((*balancesMap)[qsAddr] + it["value"].get<json::number_float_t>()) /10000000;
}
};
@@ -279,26 +283,28 @@ void Controller::refreshBalances() {
// 1. Get the Balances
zrpc->fetchBalance([=] (json reply) {
auto balT = reply["tbalance"].get<json::number_unsigned_t>();
auto balZ = reply["zbalance"].get<json::number_unsigned_t>();
auto balT = reply["tbalance"].get<json::number_float_t>();
auto balZ = reply["zbalance"].get<json::number_float_t>();
auto balTotal = balT + balZ;
AppDataModel::getInstance()->setBalances(balT, balZ);
ui->balSheilded ->setText(Settings::gethushDisplayFormat(balZ));
ui->balTransparent->setText(Settings::gethushDisplayFormat(balT));
ui->balTotal ->setText(Settings::gethushDisplayFormat(balTotal));
ui->balSheilded ->setText(Settings::gethushDisplayFormat(balZ /10000000));
ui->balTransparent->setText(Settings::gethushDisplayFormat(balT /10000000));
ui->balTotal ->setText(Settings::gethushDisplayFormat(balTotal /10000000));
ui->balSheilded ->setToolTip(Settings::gethushDisplayFormat(balZ));
ui->balTransparent->setToolTip(Settings::gethushDisplayFormat(balT));
ui->balTotal ->setToolTip(Settings::gethushDisplayFormat(balTotal));
ui->balSheilded ->setToolTip(Settings::gethushDisplayFormat(balZ /10000000));
ui->balTransparent->setToolTip(Settings::gethushDisplayFormat(balT /10000000));
ui->balTotal ->setToolTip(Settings::gethushDisplayFormat(balTotal /10000000));
});
// 2. Get the UTXOs
// First, create a new UTXO list. It will be replacing the existing list when everything is processed.
auto newUtxos = new QList<UnspentOutput>();
auto newBalances = new QMap<QString, qint64>();
auto newBalances = new QMap<QString, double>();
// Call the Transparent and Z unspent APIs serially and then, once they're done, update the UI
zrpc->fetchUnspent([=] (json reply) {
@@ -323,7 +329,7 @@ void Controller::refreshTransactions() {
for (auto& it : reply.get<json::array_t>()) {
QString address;
qint64 total_amount;
double total_amount;
QList<TransactionItemDetail> items;
// First, check if there's outgoing metadata
@@ -331,7 +337,7 @@ void Controller::refreshTransactions() {
for (auto o: it["outgoing_metadata"].get<json::array_t>()) {
QString address = QString::fromStdString(o["address"]);
qint64 amount = -1 * o["value"].get<json::number_integer_t>(); // Sent items are -ve
double amount = -1 * o["value"].get<json::number_float_t>() /10000000;// Sent items are -ve
QString memo;
if (!o["memo"].is_null()) {
@@ -353,7 +359,7 @@ void Controller::refreshTransactions() {
it["datetime"].get<json::number_unsigned_t>(),
address,
QString::fromStdString(it["txid"]),
model->getLatestBlock() - it["block_height"].get<json::number_unsigned_t>(),
model->getLatestBlock() - it["block_height"].get<json::number_unsigned_t>(),
items
});
} else {
@@ -363,7 +369,7 @@ void Controller::refreshTransactions() {
items.push_back(TransactionItemDetail{
address,
it["amount"].get<json::number_integer_t>(),
it["amount"].get<json::number_float_t>(),
""
});
@@ -417,7 +423,7 @@ void Controller::executeTransaction(Tx tx,
std::cout << std::setw(2) << params << std::endl;
zrpc->sendTransaction(QString::fromStdString(params.dump()), [=](const json& reply) {
if (reply["result"].is_null() || reply["result"] != "success") {
if (reply.find("txid") == reply.end()) {
error("", "Couldn't understand Response: " + QString::fromStdString(reply.dump()));
}
@@ -508,11 +514,12 @@ void Controller::refreshhushPrice() {
if (!zrpc->haveConnection())
return noConnection();
QUrl cmcURL("https://api.coingecko.com/api/v3/simple/price?ids=hush&vs_currencies=btc%2Cusd%2Ceur&include_market_cap=true&include_24hr_vol=true&include_24hr_change=true");
// TODO: use/render all this data
QUrl cmcURL("ncies=btc%2Cusd%2Ceur&include_market_cap=true&include_24hr_vol=true&include_24hr_change=true");
QNetworkRequest req;
req.setUrl(cmcURL);
QNetworkAccessManager *manager = new QNetworkAccessManager(this->main);
QNetworkReply *reply = manager->get(req);
@@ -524,34 +531,41 @@ void Controller::refreshhushPrice() {
if (reply->error() != QNetworkReply::NoError) {
auto parsed = json::parse(reply->readAll(), nullptr, false);
if (!parsed.is_discarded() && !parsed["error"]["message"].is_null()) {
qDebug() << QString::fromStdString(parsed["error"]["message"]);
qDebug() << QString::fromStdString(parsed["error"]["message"]);
} else {
qDebug() << reply->errorString();
}
Settings::getInstance()->sethushPrice(0);
return;
}
}
qDebug() << "No network errors";
auto all = reply->readAll();
auto parsed = json::parse(all, nullptr, false);
if (parsed.is_discarded()) {
Settings::getInstance()->sethushPrice(0);
return;
}
for (const json& item : parsed.get<json::array_t>()) {
if (item["symbol"].get<json::string_t>() == Settings::getTokenName().toStdString()) {
QString price = QString::fromStdString(item["price_usd"].get<json::string_t>());
qDebug() << Settings::getTokenName() << " Price=" << price;
Settings::getInstance()->sethushPrice(price.toDouble());
qDebug() << "Parsed JSON";
return;
}
const json& item = parsed.get<json::object_t>();
const json& hush = item["Hush"].get<json::object_t>();
if (hush["usd"] >= 0) {
qDebug() << "Found hush key in price json";
// TODO: support BTC/EUR prices as well
QString price = QString::fromStdString(hush["usd"].get<json::string_t>());
qDebug() << "HUSH = $" << QString::number((double)hush["usd"]);
Settings::getInstance()->sethushPrice( hush["usd"] );
return;
} else {
qDebug() << "No hush key found in JSON! API might be down or we are rate-limited\n";
}
} catch (...) {
} catch (const std::exception& e) {
// If anything at all goes wrong, just set the price to 0 and move on.
qDebug() << QString("Caught something nasty");
qDebug() << QString("Caught something nasty: ") << e.what();
}
// If nothing, then set the price to 0;
@@ -560,115 +574,28 @@ void Controller::refreshhushPrice() {
}
void Controller::shutdownhushd() {
// Shutdown embedded hushd if it was started
if (ehushd == nullptr || ehushd->processId() == 0 || !zrpc->haveConnection()) {
// No hushd running internally, just return
return;
// Save the wallet and exit the lightclient library cleanly.
if (zrpc->haveConnection()) {
QDialog d(main);
Ui_ConnectionDialog connD;
connD.setupUi(&d);
connD.topIcon->setBasePixmap(QIcon(":/icons/res/icon.ico").pixmap(256, 256));
connD.status->setText(QObject::tr("Please wait for SilentDragonLite to exit"));
connD.statusDetail->setText(QObject::tr("Waiting for hushd to exit"));
bool finished = false;
zrpc->saveWallet([&] (json) {
if (!finished)
d.accept();
finished = true;
});
if (!finished)
d.exec();
}
// json payload = {
// {"jsonrpc", "1.0"},
// {"id", "someid"},
// {"method", "stop"}
// };
// getConnection()->doRPCWithDefaultErrorHandling(payload, [=](auto) {});
// getConnection()->shutdown();
// QDialog d(main);
// Ui_ConnectionDialog connD;
// connD.setupUi(&d);
// connD.topIcon->setBasePixmap(QIcon(":/icons/res/icon.ico").pixmap(256, 256));
// connD.status->setText(QObject::tr("Please wait for silentdragon to exit"));
// connD.statusDetail->setText(QObject::tr("Waiting for hushd to exit"));
// QTimer waiter(main);
// // We capture by reference all the local variables because of the d.exec()
// // below, which blocks this function until we exit.
// int waitCount = 0;
// QObject::connect(&waiter, &QTimer::timeout, [&] () {
// waitCount++;
// if ((ehushd->atEnd() && ehushd->processId() == 0) ||
// waitCount > 30 ||
// getConnection()->config->hushDaemon) { // If hushd is daemon, then we don't have to do anything else
// qDebug() << "Ended";
// waiter.stop();
// QTimer::singleShot(1000, [&]() { d.accept(); });
// } else {
// qDebug() << "Not ended, continuing to wait...";
// }
// });
// waiter.start(1000);
// // Wait for the hush process to exit.
// if (!Settings::getInstance()->isHeadless()) {
// d.exec();
// } else {
// while (waiter.isActive()) {
// QCoreApplication::processEvents();
// QThread::sleep(1);
// }
// }
}
// // Fetch the Z-board topics list
// void Controller::getZboardTopics(std::function<void(QMap<QString, QString>)> cb) {
// if (!zrpc->haveConnection())
// return noConnection();
// QUrl cmcURL("http://z-board.net/listTopics");
// QNetworkRequest req;
// req.setUrl(cmcURL);
// QNetworkReply *reply = conn->restclient->get(req);
// QObject::connect(reply, &QNetworkReply::finished, [=] {
// reply->deleteLater();
// try {
// if (reply->error() != QNetworkReply::NoError) {
// auto parsed = json::parse(reply->readAll(), nullptr, false);
// if (!parsed.is_discarded() && !parsed["error"]["message"].is_null()) {
// qDebug() << QString::fromStdString(parsed["error"]["message"]);
// }
// else {
// qDebug() << reply->errorString();
// }
// return;
// }
// auto all = reply->readAll();
// auto parsed = json::parse(all, nullptr, false);
// if (parsed.is_discarded()) {
// return;
// }
// QMap<QString, QString> topics;
// for (const json& item : parsed["topics"].get<json::array_t>()) {
// if (item.find("addr") == item.end() || item.find("topicName") == item.end())
// return;
// QString addr = QString::fromStdString(item["addr"].get<json::string_t>());
// QString topic = QString::fromStdString(item["topicName"].get<json::string_t>());
// topics.insert(topic, addr);
// }
// cb(topics);
// }
// catch (...) {
// // If anything at all goes wrong, just set the price to 0 and move on.
// qDebug() << QString("Caught something nasty");
// }
// });
// }
/**
* Get a Sapling address from the user's wallet
*/
+1 -1
View File
@@ -78,7 +78,7 @@ private:
void refreshTransactions();
bool processUnspent (const json& reply, QMap<QString, qint64>* newBalances, QList<UnspentOutput>* newUtxos);
bool processUnspent (const json& reply, QMap<QString, double>* newBalances, QList<UnspentOutput>* newUtxos);
void updateUI (bool anyUnconfirmed);
void getInfoThenRefresh(bool force);
+2 -2
View File
@@ -7,7 +7,7 @@ DataModel::DataModel() {
QWriteLocker locker(lock);
utxos = new QList<UnspentOutput>();
balances = new QMap<QString, qint64>();
balances = new QMap<QString, double>();
usedAddresses = new QMap<QString, bool>();
zaddresses = new QList<QString>();
taddresses = new QList<QString>();
@@ -44,7 +44,7 @@ void DataModel::replaceTaddresses(QList<QString>* newT) {
taddresses = newT;
}
void DataModel::replaceBalances(QMap<QString, qint64>* newBalances) {
void DataModel::replaceBalances(QMap<QString, double>* newBalances) {
QWriteLocker locker(lock);
Q_ASSERT(newBalances);
+4 -4
View File
@@ -18,7 +18,7 @@ class DataModel {
public:
void replaceZaddresses(QList<QString>* newZ);
void replaceTaddresses(QList<QString>* newZ);
void replaceBalances(QMap<QString, qint64>* newBalances);
void replaceBalances(QMap<QString, double>* newBalances);
void replaceUTXOs(QList<UnspentOutput>* utxos);
void markAddressUsed(QString address);
@@ -29,8 +29,8 @@ public:
const QList<QString> getAllZAddresses() { QReadLocker locker(lock); return *zaddresses; }
const QList<QString> getAllTAddresses() { QReadLocker locker(lock); return *taddresses; }
const QList<UnspentOutput> getUTXOs() { QReadLocker locker(lock); return *utxos; }
const QMap<QString, qint64> getAllBalances() { QReadLocker locker(lock); return *balances; }
const QMap<QString, bool> getUsedAddresses() { QReadLocker locker(lock); return *usedAddresses; }
const QMap<QString, double> getAllBalances() { QReadLocker locker(lock); return *balances; }
const QMap<QString, bool> getUsedAddresses() { QReadLocker locker(lock); return *usedAddresses; }
DataModel();
@@ -39,7 +39,7 @@ private:
int latestBlock;
QList<UnspentOutput>* utxos = nullptr;
QMap<QString, qint64>* balances = nullptr;
QMap<QString, double>* balances = nullptr;
QMap<QString, bool>* usedAddresses = nullptr;
QList<QString>* zaddresses = nullptr;
QList<QString>* taddresses = nullptr;
+178
View File
@@ -0,0 +1,178 @@
#include "firsttimewizard.h"
#include "ui_newseed.h"
#include "ui_restoreseed.h"
#include "ui_newwallet.h"
#include "../lib/silentdragonlitelib.h"
using json = nlohmann::json;
FirstTimeWizard::FirstTimeWizard(bool dangerous, QString server)
{
setWindowTitle("New wallet wizard");
this->dangerous = dangerous;
this->server = server;
// Create the pages
setPage(Page_NewOrRestore, new NewOrRestorePage(this));
setPage(Page_New, new NewSeedPage(this));
setPage(Page_Restore,new RestoreSeedPage(this));
}
int FirstTimeWizard::nextId() const {
switch (currentId()) {
case Page_NewOrRestore:
if (field("intro.new").toBool()) {
return Page_New;
} else {
return Page_Restore;
}
case Page_New:
case Page_Restore:
default:
return -1;
}
}
NewOrRestorePage::NewOrRestorePage(FirstTimeWizard *parent) : QWizardPage(parent) {
setTitle("Create or Restore wallet.");
QWidget* pageWidget = new QWidget();
Ui_CreateWalletForm form;
form.setupUi(pageWidget);
// Exclusive buttons
QObject::connect(form.radioNewWallet, &QRadioButton::clicked, [=](bool checked) {
if (checked) {
form.radioRestoreWallet->setChecked(false);
}
});
QObject::connect(form.radioRestoreWallet, &QRadioButton::clicked, [=](bool checked) {
if (checked) {
form.radioNewWallet->setChecked(false);
}
});
form.radioNewWallet->setChecked(true);
registerField("intro.new", form.radioNewWallet);
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(pageWidget);
setLayout(layout);
setCommitPage(true);
setButtonText(QWizard::CommitButton, "Next");
}
NewSeedPage::NewSeedPage(FirstTimeWizard *parent) : QWizardPage(parent) {
this->parent = parent;
setTitle("Your new wallet");
QWidget* pageWidget = new QWidget();
form.setupUi(pageWidget);
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(pageWidget);
setLayout(layout);
}
void NewSeedPage::initializePage() {
// Call the library to create a new wallet.
char* resp = litelib_initialize_new(parent->dangerous, parent->server.toStdString().c_str());
QString reply = litelib_process_response(resp);
auto parsed = json::parse(reply.toStdString().c_str(), nullptr, false);
if (parsed.is_discarded() || parsed.is_null() || parsed.find("seed") == parsed.end()) {
form.txtSeed->setPlainText(tr("Error creating a wallet") + "\n" + reply);
} else {
QString seed = QString::fromStdString(parsed["seed"].get<json::string_t>());
form.txtSeed->setPlainText(seed);
}
}
// Will be called just before closing. Make sure we can save the seed in the wallet
// before we allow the page to be closed
bool NewSeedPage::validatePage() {
char* resp = litelib_execute("save", "");
QString reply = litelib_process_response(resp);
auto parsed = json::parse(reply.toStdString().c_str(), nullptr, false);
if (parsed.is_discarded() || parsed.is_null() || parsed.find("result") == parsed.end()) {
QMessageBox::warning(this, tr("Failed to save wallet"),
tr("Couldn't save the wallet") + "\n" + reply,
QMessageBox::Ok);
return false;
} else {
return true;
}
}
RestoreSeedPage::RestoreSeedPage(FirstTimeWizard *parent) : QWizardPage(parent) {
this->parent = parent;
setTitle("Restore wallet from seed");
QWidget* pageWidget = new QWidget();
form.setupUi(pageWidget);
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(pageWidget);
setLayout(layout);
}
bool RestoreSeedPage::validatePage() {
// 1. Validate that we do have 24 words
QString seed = form.txtSeed->toPlainText().replace(QRegExp("[ \n\r\t]+"), " ");
if (seed.trimmed().split(" ").length() != 24) {
QMessageBox::warning(this, tr("Failed to restore wallet"),
tr("SilentDragonLite needs 24 words to restore wallet"),
QMessageBox::Ok);
return false;
}
// 2. Validate birthday
QString birthday_str = form.txtBirthday->text();
bool ok;
qint64 birthday = birthday_str.toUInt(&ok);
if (!ok) {
QMessageBox::warning(this, tr("Failed to parse wallet birthday"),
tr("Couldn't understand wallet birthday. This should be a block height from where to rescan the wallet. You can leave it as '0' if you don't know what it should be."),
QMessageBox::Ok);
return false;
}
// 3. Attempt to restore wallet with the seed phrase
{
char* resp = litelib_initialize_new_from_phrase(parent->dangerous, parent->server.toStdString().c_str(),
seed.toStdString().c_str(), birthday);
QString reply = litelib_process_response(resp);
if (reply.toUpper().trimmed() != "OK") {
QMessageBox::warning(this, tr("Failed to restore wallet"),
tr("Couldn't restore the wallet") + "\n" + reply,
QMessageBox::Ok);
return false;
}
}
// 4. Finally attempt to save the wallet
{
char* resp = litelib_execute("save", "");
QString reply = litelib_process_response(resp);
auto parsed = json::parse(reply.toStdString().c_str(), nullptr, false);
if (parsed.is_discarded() || parsed.is_null() || parsed.find("result") == parsed.end()) {
QMessageBox::warning(this, tr("Failed to save wallet"),
tr("Couldn't save the wallet") + "\n" + reply,
QMessageBox::Ok);
return false;
} else {
return true;
}
}
}
+66
View File
@@ -0,0 +1,66 @@
#ifndef FIRSTTIMEWIZARD_H
#define FIRSTTIMEWIZARD_H
#include "precompiled.h"
#include "ui_newseed.h"
#include "ui_restoreseed.h"
class FirstTimeWizard: public QWizard
{
public:
FirstTimeWizard(bool dangerous, QString server);
protected:
int nextId() const;
private:
enum {
Page_NewOrRestore,
Page_New,
Page_Restore
};
bool dangerous;
QString server;
friend class NewOrRestorePage;
friend class NewSeedPage;
friend class RestoreSeedPage;
};
class NewOrRestorePage: public QWizardPage {
public:
NewOrRestorePage(FirstTimeWizard* parent);
};
class NewSeedPage: public QWizardPage {
public:
NewSeedPage(FirstTimeWizard* parent);
protected:
virtual void initializePage();
virtual bool validatePage();
private:
FirstTimeWizard* parent;
Ui_NewSeedForm form;
};
class RestoreSeedPage: public QWizardPage {
public:
RestoreSeedPage(FirstTimeWizard* parent);
protected:
bool validatePage();
private:
FirstTimeWizard* parent;
Ui_RestoreSeedForm form;
};
#endif // FIRSTTIMEWIZARD_H
+8 -1
View File
@@ -39,7 +39,7 @@ void LiteInterface::createNewZaddr(bool, const std::function<void(json)>& cb) {
if (conn == nullptr)
return;
conn->doRPCWithDefaultErrorHandling("new", "zs", cb);
conn->doRPCWithDefaultErrorHandling("new", "zs1", cb);
}
void LiteInterface::createNewTaddr(const std::function<void(json)>& cb) {
@@ -70,6 +70,13 @@ void LiteInterface::fetchTransactions(const std::function<void(json)>& cb) {
conn->doRPCWithDefaultErrorHandling("list", "", cb);
}
void LiteInterface::saveWallet(const std::function<void(json)>& cb) {
if (conn == nullptr)
return;
conn->doRPCWithDefaultErrorHandling("save", "", cb);
}
void LiteInterface::sendTransaction(QString params, const std::function<void(json)>& cb,
const std::function<void(QString)>& err) {
if (conn == nullptr)
+5 -2
View File
@@ -11,7 +11,7 @@ using json = nlohmann::json;
// into a struct with address, amount, memo
struct TransactionItemDetail {
QString address;
qint64 amount;
double amount;
QString memo;
};
@@ -45,12 +45,15 @@ public:
const std::function<void(QString)>& err);
void fetchBalance(const std::function<void(json)>& cb);
void createNewZaddr(bool sapling, const std::function<void(json)>& cb);
void createNewTaddr(const std::function<void(json)>& cb);
void fetchPrivKey(QString addr, const std::function<void(json)>& cb);
void fetchAllPrivKeys(const std::function<void(json)>);
void fetchAllPrivKeys(const std::function<void(json)>);
void saveWallet(const std::function<void(json)>& cb);
//void importZPrivKey(QString addr, bool rescan, const std::function<void(json)>& cb);
//void importTPrivKey(QString addr, bool rescan, const std::function<void(json)>& cb);
+1 -1
View File
@@ -25,7 +25,7 @@ struct ToFields {
struct Tx {
QString fromAddr;
QList<ToFields> toAddrs;
double fee;
double fee;
};
namespace Ui {
+12 -12
View File
@@ -22,7 +22,7 @@
<item row="0" column="0">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>2</number>
<number>4</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
@@ -935,7 +935,7 @@
<item row="5" column="0" colspan="3">
<widget class="QLabel" name="label_14">
<property name="text">
<string>You are currently not mining</string>
<string>This is a Lightwallet, you cant mine with it!</string>
</property>
</widget>
</item>
@@ -953,7 +953,7 @@
</spacer>
</item>
<item row="2" column="2">
<widget class="QLabel" name="numconnections">
<widget class="QLabel" name="version">
<property name="text">
<string>Loading...</string>
</property>
@@ -962,12 +962,12 @@
<item row="1" column="0">
<widget class="QLabel" name="heightLabel">
<property name="text">
<string>Block height</string>
<string>Blockheight</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QLabel" name="solrate">
<widget class="QLabel" name="Vendor">
<property name="text">
<string>Loading...</string>
</property>
@@ -976,19 +976,19 @@
<item row="3" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Network solution rate</string>
<string>Version hushd light</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Connections</string>
<string>Vendor</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="blockheight">
<widget class="QLabel" name="blockHeight">
<property name="text">
<string>Loading...</string>
</property>
@@ -1122,17 +1122,17 @@
<property name="text">
<string>&amp;Send Duke Feedback</string>
</property>
</action>
</action>
<action name="actionDiscord">
<property name="text">
<string>&amp;Hush Discord</string>
</property>
</action>
<action name="actionWebsite">
</action>
<action name="actionWebsite">
<property name="text">
<string>&amp;Hush Website</string>
</property>
</action>
</action>
<action name="actionCheck_for_Updates">
<property name="text">
<string>Check github.com for &amp;updates</string>
+63
View File
@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NewSeedForm</class>
<widget class="QWidget" name="NewSeedForm">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>This is your new wallet's seed phrase. PLEASE BACK IT UP SECURELY.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>The seed phrase is the only way to restore the wallet. If you forget the seed phrase, THERE IS NO WAY TO RESTORE YOUR WALLET AND THE FUNDS in it</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string/>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPlainTextEdit" name="txtSeed">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
+85
View File
@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CreateWalletForm</class>
<widget class="QWidget" name="CreateWalletForm">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string/>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QRadioButton" name="radioRestoreWallet">
<property name="text">
<string>Restore wallet from seed</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Restore an existing wallet, using the 24-word seed. </string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string/>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QRadioButton" name="radioNewWallet">
<property name="text">
<string>Create a new Wallet</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Create a new wallet with a randomly generated seed.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
+2
View File
@@ -17,6 +17,8 @@
#include <QAbstractTableModel>
#include <QTranslator>
#include <QClipboard>
#include <QWizard>
#include <QWizardPage>
#include <QStringBuilder>
#include <QAbstractItemModel>
#include <QTableView>
+89
View File
@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>RestoreSeedForm</class>
<widget class="QWidget" name="RestoreSeedForm">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Please enter your 24-word seed below</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string/>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Wallet Seed</string>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="txtSeed">
<property name="readOnly">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Wallet Birthday</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="txtBirthday">
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="font">
<font>
<pointsize>9</pointsize>
</font>
</property>
<property name="text">
<string>Wallet birthday is the block height at which the wallet had the first transaction. If you don't know this, you can leave it as &quot;0&quot; (It'll take longer to rescan)</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
+1 -1
View File
@@ -315,7 +315,7 @@ bool Settings::removeFromhushConf(QString confLocation, QString option) {
}
double Settings::getMinerFee() {
return 0.0001;
return 0.01;
}
double Settings::getZboardAmount() {
+2
View File
@@ -119,6 +119,8 @@ public:
static bool addTohushConf(QString confLocation, QString line);
static bool removeFromhushConf(QString confLocation, QString option);
static QString getChainName() { return QString("test"); }
static const QString labelRegExp;
static const int updateSpeed = 20 * 1000; // 10 sec