From a478a79e8b07d958ed5a976c0bad09ec30b4893f Mon Sep 17 00:00:00 2001 From: Cheng Date: Fri, 24 Feb 2023 11:33:09 +0800 Subject: [PATCH 1/7] handle exception while attempting to open an existing wallet --- src/frame.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/frame.cpp b/src/frame.cpp index 221b8fc..ad3731a 100644 --- a/src/frame.cpp +++ b/src/frame.cpp @@ -65,7 +65,7 @@ Frame::Frame(wxString wxs) m_panel(), m_LastUsedSqlite() { -try { + try { assert(singletonFrame == nullptr); singletonFrame = this; SetIcon(wxICON(AAArho)); @@ -150,14 +150,22 @@ try { menuBar->EnableTop(1, false); //disable edit menu. // child controls m_LastUsedSqlite.Assign(singletonApp->pConfig->Read(wxT("/Wallet/LastUsed"), wxT(""))); - if (!m_LastUsedSqlite.IsOk() || !m_LastUsedSqlite.HasName() || !m_LastUsedSqlite.HasExt()) { - m_panel = new welcome_to_rhocoin(this); //Owner is "this", via the base class wxFrame. m_panel is a + wxPanel* panel{ nullptr }; + try { + if (m_LastUsedSqlite.IsOk()) + { //Try to load an existing file. + panel = new display_wallet(this, m_LastUsedSqlite); + } + else { + panel = new welcome_to_rhocoin(this); + } + } + catch (const std::exception& e) { + queue_error_message(e.what()); + panel = new welcome_to_rhocoin(this); //Owner is "this", via the base class wxFrame. m_panel is a // non owning pointer in the derived class that duplicates the owning pointer in the base class. } - else { - display_wallet* panel = new display_wallet(this, m_LastUsedSqlite); - m_panel = panel; - } + m_panel = panel; this->RestorePositionFromConfig(ClientToWindowSize(m_panel->GetBestSize())); SetClientSize(GetClientSize()); } From 5b37e32a8163e1c963466640eb9b836bc50cb87b Mon Sep 17 00:00:00 2001 From: Cheng Date: Fri, 24 Feb 2023 13:30:54 +0800 Subject: [PATCH 2/7] fixed add name UI Error handling in add name still horribly broken --- src/db_accessors.h | 7 +++++-- src/display_wallet.cpp | 8 ++++---- src/frame.cpp | 11 +++++++++-- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/db_accessors.h b/src/db_accessors.h index c065d62..e88708c 100644 --- a/src/db_accessors.h +++ b/src/db_accessors.h @@ -183,12 +183,15 @@ class sql_insert_name { ro::sql csql_into_names; ro::sql csql_namekey_into_keys; ro::sql csql_commit; + ro::sql csql_rollback; public: sql_insert_name(ISqlite3* p) : csql_begin(p, R"|(BEGIN;)|"), csql_into_names(p, R"|(INSERT OR ROLLBACK INTO "Names" VALUES(?1);)|"), csql_namekey_into_keys(p, R"|(INSERT OR ROLLBACK INTO "Keys" VALUES(?1, last_insert_rowid(), 1);)|"), - csql_commit(p, R"|(COMMIT;)|") {} + csql_commit(p, R"|(COMMIT;)|"), + csql_rollback(p, R"|(ROLLBACK;)|") + {} sql_insert_name(const std::unique_ptr& p) : sql_insert_name(p.get()) {} void operator()(const char* psz, const ristretto255::point& pt) { csql_begin.do_one(); @@ -197,7 +200,7 @@ public: csql_namekey_into_keys.do_one(pt); } catch (const std::exception & e) { - csql_commit.do_one(); + csql_rollback.do_one(); throw e; } csql_commit.do_one(); diff --git a/src/display_wallet.cpp b/src/display_wallet.cpp index 133f485..9430788 100644 --- a/src/display_wallet.cpp +++ b/src/display_wallet.cpp @@ -79,10 +79,10 @@ void display_wallet::close_menu_event_handler(wxCommandEvent& event) { void display_wallet::add_name_event_handler(wxCommandEvent& event) { wxTextEntryDialog dialog(this, - "This is a small sample\n" - "A long, long string to test out the text entrybox", - "Please enter a string", - "Default value", + R"("A Zooko name has a human readable name, +and a public key defined by the name and the wallet master secret)", + "Create a Zooko name", + "", wxOK | wxCANCEL); if (dialog.ShowModal() == wxID_OK) { diff --git a/src/frame.cpp b/src/frame.cpp index ad3731a..6bcac83 100644 --- a/src/frame.cpp +++ b/src/frame.cpp @@ -161,10 +161,17 @@ Frame::Frame(wxString wxs) } } catch (const std::exception& e) { + // if the attempt to load an existing wallet file fails, + // we have to complete startup somehow. + queue_error_message(e.what()); - panel = new welcome_to_rhocoin(this); //Owner is "this", via the base class wxFrame. m_panel is a - // non owning pointer in the derived class that duplicates the owning pointer in the base class. + panel = new welcome_to_rhocoin(this); //Owner is "this", via the base class wxFrame. } + // m_panel is a non owning pointer in the derived class that duplicates the + // owning pointer in the base class. This looks like a violation of DIY. + // but I have the concept of the primary child of the frame window, while + // wxWidgets lacks that concept. + // m_panel signifies the child window of the frame that currently matters. m_panel = panel; this->RestorePositionFromConfig(ClientToWindowSize(m_panel->GetBestSize())); SetClientSize(GetClientSize()); From badd99b74b65925f079b4cc0835356581816d193 Mon Sep 17 00:00:00 2001 From: Cheng Date: Sat, 25 Feb 2023 15:46:07 +0800 Subject: [PATCH 3/7] now does correct error handling on insert name But not very user friendly --- src/db_accessors.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/db_accessors.h b/src/db_accessors.h index e88708c..c13717e 100644 --- a/src/db_accessors.h +++ b/src/db_accessors.h @@ -187,8 +187,8 @@ class sql_insert_name { public: sql_insert_name(ISqlite3* p) : csql_begin(p, R"|(BEGIN;)|"), - csql_into_names(p, R"|(INSERT OR ROLLBACK INTO "Names" VALUES(?1);)|"), - csql_namekey_into_keys(p, R"|(INSERT OR ROLLBACK INTO "Keys" VALUES(?1, last_insert_rowid(), 1);)|"), + csql_into_names(p, R"|(INSERT OR FAIL INTO "Names" VALUES(?1);)|"), + csql_namekey_into_keys(p, R"|(INSERT OR FAIL INTO "Keys" VALUES(?1, last_insert_rowid(), 1);)|"), csql_commit(p, R"|(COMMIT;)|"), csql_rollback(p, R"|(ROLLBACK;)|") {} @@ -199,9 +199,9 @@ public: csql_into_names.do_one(psz); csql_namekey_into_keys.do_one(pt); } - catch (const std::exception & e) { + catch (const std::exception &) { csql_rollback.do_one(); - throw e; + throw; } csql_commit.do_one(); } From 61db53576970e610224faa0eb0b6432a49ef8d2e Mon Sep 17 00:00:00 2001 From: Cheng Date: Sat, 25 Feb 2023 22:05:53 +0800 Subject: [PATCH 4/7] user friendly error handling of zooko names Fixed it while dead drunk could not walk in a straight line had difficulty typing coded rather slowly, but still wrote smart code. Realized that the error handling has to have exception structures in scope, but not the constructors in scope You can forward the constructors, but if you forward the structs, exceptions will crash. Your exception constructor inputs can use structs that are out of scope at the exception handler --- src/ILog.h | 18 ++++++++++-------- src/ISqlit3Impl.cpp | 19 ++++++++++++------- src/db_accessors.h | 12 +++++++++++- src/localization.cpp | 2 -- 4 files changed, 33 insertions(+), 18 deletions(-) diff --git a/src/ILog.h b/src/ILog.h index 2a55c96..bee8b24 100644 --- a/src/ILog.h +++ b/src/ILog.h @@ -10,17 +10,25 @@ void ILogDebug(const char*); void queue_error_message(const char*); //Used for error conditions within a destructor because you cannot throw within a destructor void queue_fatal_error(const char*); //Used for fatal error conditions within a destructor in place of FatalException because you cannot throw within a destructor +struct sqlite3; + class MyException: public std::exception { private: std::string err; + int err_number; public: virtual ~MyException() override = default; MyException() = delete; - explicit MyException(const std::string &m) noexcept :err(m){} - explicit MyException(const char* sz) noexcept :err(sz) {} + explicit MyException(const std::string &m) noexcept :err(m.c_str()),err_number(-1){} + explicit MyException(const char* sz) noexcept :err(sz),err_number(-1) {} + explicit MyException(const char* sz, int i) noexcept :err(sz), err_number(i) {} + explicit MyException(int, sqlite3*) noexcept; virtual const char* what() const override { return err.c_str(); } + virtual const int what_num() const { + return err_number; + } }; class FatalException : public MyException { @@ -35,12 +43,6 @@ public: HashReuseException() noexcept; }; -class SQLexception : public MyException { -public: - using MyException::MyException; - SQLexception() noexcept; -}; - class NonUtf8DataInDatabase : public MyException { public: using MyException::MyException; diff --git a/src/ISqlit3Impl.cpp b/src/ISqlit3Impl.cpp index cebd543..20ec69f 100644 --- a/src/ISqlit3Impl.cpp +++ b/src/ISqlit3Impl.cpp @@ -24,7 +24,7 @@ void sqlite3_init() { if (sqlite3_initialize() != SQLITE_OK) { errorCode = 7; szError = "Fatal Error: Sqlite library did not init."; -// Cannot log the error, because logging not set up yet, so logging itself causes an exception + // Cannot log the error, because logging not set up yet, so logging itself causes an exception throw FatalException(szError.c_str()); } } @@ -35,7 +35,7 @@ static int callback(void* NotUsed, int argc, char** argv, char** azColName) { std::string str; str.reserve(256); for (int i = 0; i < argc; i++) { - str =str + "\t\"" + azColName[i]+ R"|("=)|" + (argv[i]!=nullptr ? argv[i] : "NULL"); + str = str + "\t\"" + azColName[i] + R"|("=)|" + (argv[i] != nullptr ? argv[i] : "NULL"); } ILogMessage(str.c_str()); return 0; @@ -52,7 +52,7 @@ public: pdb = nullptr; #endif int rc =sqlite3_open_v2(dbName, &pdb, flags, nullptr); - if (rc != SQLITE_OK) throw SQLexception(error_message(rc, pdb)); + if (rc != SQLITE_OK) throw MyException(rc, pdb); assert(pdb != nullptr); // pdb can never be nullptr, since the sqlite3_open_v2 command always initializes // it even if open fails @@ -62,7 +62,7 @@ public: char* zErrMsg = nullptr; int rc = sqlite3_exec(pdb, szsql, callback, nullptr, &zErrMsg); if (rc != SQLITE_OK) { - SQLexception e(std::string("SQL Exec Error: ") + zErrMsg); + auto e = MyException(zErrMsg, rc); sqlite3_free(zErrMsg); throw e; } @@ -90,6 +90,11 @@ ISqlite3* Sqlite3_open(const char * db_name) { return new ISqlite3Impl(db_name, SQLITE_OPEN_READWRITE); } +MyException::MyException(int i, sqlite3* pdb) noexcept: + err_number(i), + err(error_message(i, pdb)) +{} + // Factory method to create database. ISqlite3 * Sqlite3_create(const char* db_name) { return new ISqlite3Impl(db_name, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); @@ -101,10 +106,10 @@ class IcompiledImpl_sql : friend class ISqlite3Impl; private: sqlite3_stmt *pStmt; - ISqlite3Impl *pdbImplOwn; + ISqlite3Impl*pdbImplOwn; auto e(int rc) { assert(rc != SQLITE_OK); - return SQLexception(error_message(rc, pdbImplOwn->pdb)); + return MyException(rc, pdbImplOwn->pdb); } public: IcompiledImpl_sql() = delete; @@ -192,7 +197,7 @@ public: // from n blocks to n+1 blocks when a single transaction updates the root and anciliary data. // We will build the blockchain hash table in postfix format, with patricia tree nodes that // have skiplink format stored only in memory and rebuilt each startup so that it grows append only, - throw SQLexception("Abnormal busy database"); + throw MyException("Abnormal busy database", 2^14+2); break; case SQLITE_MISUSE: //ret = MISUSE; diff --git a/src/db_accessors.h b/src/db_accessors.h index c13717e..12172d3 100644 --- a/src/db_accessors.h +++ b/src/db_accessors.h @@ -114,8 +114,9 @@ namespace ro { result step() { return (*this)->Isqlite3_step(); } + void final_step() { - if (step() != result::DONE) throw SQLexception("SQL: Unexpected rows remaining"); + if (step() != result::DONE) throw MyException("SQL: Unexpected rows remaining", 16384); } void reset() { (*this)->Isqlite3_reset(); @@ -199,6 +200,15 @@ public: csql_into_names.do_one(psz); csql_namekey_into_keys.do_one(pt); } + catch (const MyException& e) { + csql_rollback.do_one(); + if (e.what_num() == 19) { + throw MyException("Name already in database"); + } + else { + throw; + } + } catch (const std::exception &) { csql_rollback.do_one(); throw; diff --git a/src/localization.cpp b/src/localization.cpp index 10aca9a..03c35ed 100644 --- a/src/localization.cpp +++ b/src/localization.cpp @@ -129,8 +129,6 @@ FatalException::FatalException() noexcept : MyException(R"|(unspecified fatal exception)|") {}; HashReuseException::HashReuseException() noexcept : MyException(R"|(finalized the same hash constructor twice or more)|") {}; -SQLexception::SQLexception() noexcept : - MyException(R"|(SQL Exception)|") {}; BadDataException::BadDataException() noexcept : MyException(R"|(Bad data exception)|") {}; NonUtf8DataInDatabase::NonUtf8DataInDatabase() noexcept : From ce010ab1fd674506e6d921bfc8cba057a20426a6 Mon Sep 17 00:00:00 2001 From: Cheng Date: Mon, 27 Feb 2023 13:09:20 +0800 Subject: [PATCH 5/7] incorporating upstream changes of submodules --- libsodium | 2 +- mpir | 2 +- src/stdafx.h | 2 +- wxWidgets | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libsodium b/libsodium index 8cbcc3c..bc41d89 160000 --- a/libsodium +++ b/libsodium @@ -1 +1 @@ -Subproject commit 8cbcc3ccccb035b1a976c053ab4de47b7f0b9352 +Subproject commit bc41d89b684b0068124753aba7188a3c730101cf diff --git a/mpir b/mpir index c7f9435..bc42eee 160000 --- a/mpir +++ b/mpir @@ -1 +1 @@ -Subproject commit c7f9435392ede4c7f2c887a44d7a9ca7d724f4dc +Subproject commit bc42eee0b5d04b508b196231165a567db9f8f4b6 diff --git a/src/stdafx.h b/src/stdafx.h index d32b46b..f094218 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -62,7 +62,7 @@ constexpr bool b_WINDOWS = false; static_assert(wxUSE_UNSAFE_WXSTRING_CONV == 1, R"(In fully utf environment, (wallet.manifest plus /utf-8 compile option) all string conversions are safe.)"); -static_assert(wxMAJOR_VERSION == 3 && wxMINOR_VERSION == 2 && wxRELEASE_NUMBER == 0 && wxSUBRELEASE_NUMBER == 1, "expecting wxWidgets 3.1.7"); +static_assert(wxMAJOR_VERSION == 3 && wxMINOR_VERSION == 2 && wxRELEASE_NUMBER == 2 && wxSUBRELEASE_NUMBER == 1, "expecting wxWidgets 3.2.2.1"); static_assert(wxUSE_IPV6 == 1, "IP6 unavailable in wxWidgets"); static_assert(WXWIN_COMPATIBILITY_3_0 == 0, "wxWidgets api out of date"); static_assert(wxUSE_COMPILER_TLS == (b_WINDOWS ? 2 : 1), "out of date workarounds in wxWidgets for windows bugs"); diff --git a/wxWidgets b/wxWidgets index 2648eb4..02e885c 160000 --- a/wxWidgets +++ b/wxWidgets @@ -1 +1 @@ -Subproject commit 2648eb4da156a751a377cfe96b91faa03e535c10 +Subproject commit 02e885c6f079c6e12a632f92cd7cfcceecf0c39b From 2d8aa233be55c4a7769d73897649b704b7773a3a Mon Sep 17 00:00:00 2001 From: Cheng Date: Sun, 14 May 2023 10:18:25 +0800 Subject: [PATCH 6/7] changed to immediate, and update wxWidgets version --- docs/setup/download_and_build_on_windows.md | 2 +- src/db_accessors.h | 2 +- src/frame.cpp | 2 +- src/stdafx.h | 2 +- src/unit_test.cpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/setup/download_and_build_on_windows.md b/docs/setup/download_and_build_on_windows.md index deb015e..20d4906 100644 --- a/docs/setup/download_and_build_on_windows.md +++ b/docs/setup/download_and_build_on_windows.md @@ -8,7 +8,7 @@ In a Git bash command prompt, `cd` to the directory where you intend to install the source code. ```bash -git clone --recursive git@cpal.pw:~/wallet +git clone --recursive git@rho.la:~/wallet ``` Then launch the visual studio X64 native tools command prompt. `cd` to the diff --git a/src/db_accessors.h b/src/db_accessors.h index 12172d3..72c037c 100644 --- a/src/db_accessors.h +++ b/src/db_accessors.h @@ -187,7 +187,7 @@ class sql_insert_name { ro::sql csql_rollback; public: sql_insert_name(ISqlite3* p) : - csql_begin(p, R"|(BEGIN;)|"), + csql_begin(p, R"|(BEGIN IMMEDIATE;)|"), csql_into_names(p, R"|(INSERT OR FAIL INTO "Names" VALUES(?1);)|"), csql_namekey_into_keys(p, R"|(INSERT OR FAIL INTO "Keys" VALUES(?1, last_insert_rowid(), 1);)|"), csql_commit(p, R"|(COMMIT;)|"), diff --git a/src/frame.cpp b/src/frame.cpp index 6bcac83..7483213 100644 --- a/src/frame.cpp +++ b/src/frame.cpp @@ -245,7 +245,7 @@ void Frame::NewWallet(wxFileName& filename, ristretto255::hash<256>& secret) { db->exec(R"|( PRAGMA journal_mode = WAL; PRAGMA synchronous = 1; -BEGIN TRANSACTION; +BEGIN IMMEDIATE TRANSACTION; CREATE TABLE "Keys"( "pubkey" BLOB NOT NULL UNIQUE PRIMARY KEY, "id" integer NOT NULL, diff --git a/src/stdafx.h b/src/stdafx.h index f094218..b578fed 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -62,7 +62,7 @@ constexpr bool b_WINDOWS = false; static_assert(wxUSE_UNSAFE_WXSTRING_CONV == 1, R"(In fully utf environment, (wallet.manifest plus /utf-8 compile option) all string conversions are safe.)"); -static_assert(wxMAJOR_VERSION == 3 && wxMINOR_VERSION == 2 && wxRELEASE_NUMBER == 2 && wxSUBRELEASE_NUMBER == 1, "expecting wxWidgets 3.2.2.1"); +static_assert(wxMAJOR_VERSION == 3 && wxMINOR_VERSION == 2 && wxRELEASE_NUMBER == 2 && wxSUBRELEASE_NUMBER == 1 && wxVERSION_STRING == wxT("wxWidgets 3.2.2.1"), "expecting wxWidgets 3.2.2.1"); static_assert(wxUSE_IPV6 == 1, "IP6 unavailable in wxWidgets"); static_assert(WXWIN_COMPATIBILITY_3_0 == 0, "wxWidgets api out of date"); static_assert(wxUSE_COMPILER_TLS == (b_WINDOWS ? 2 : 1), "out of date workarounds in wxWidgets for windows bugs"); diff --git a/src/unit_test.cpp b/src/unit_test.cpp index 78b045b..40f6faa 100644 --- a/src/unit_test.cpp +++ b/src/unit_test.cpp @@ -424,7 +424,7 @@ static bool OpenWallet(void) { db->exec(R"|( PRAGMA journal_mode = WAL; PRAGMA synchronous = 1; -BEGIN TRANSACTION; +BEGIN IMMEDIATE TRANSACTION; CREATE TABLE "Keys"( "pubkey" BLOB NOT NULL UNIQUE PRIMARY KEY, "id" integer NOT NULL, From c344a597a28d623bd7179b2c2fc86da11776b7e4 Mon Sep 17 00:00:00 2001 From: Cheng Date: Tue, 16 May 2023 05:30:30 +0800 Subject: [PATCH 7/7] merging upstream changes to libsodium --- libsodium | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsodium b/libsodium index bc41d89..11d0a17 160000 --- a/libsodium +++ b/libsodium @@ -1 +1 @@ -Subproject commit bc41d89b684b0068124753aba7188a3c730101cf +Subproject commit 11d0a17dbbe3f484f2b214c022d244773f26b5ec