diff --git a/src/ILog.cpp b/src/ILog.cpp index 42c492f..1fa6f2c 100644 --- a/src/ILog.cpp +++ b/src/ILog.cpp @@ -38,3 +38,12 @@ void queue_fatal_error(const char* psz) { queue_error_message(psz); singletonFrame->Close(); } + +MyException::MyException(const char* sz, int i, const char* func__, const char* FILE__) noexcept : +// usage +// throw MyException("Expected wallet file not found", __LINE__, __func__, __FILE__); + err_number(i) { + char buff[20]; + snprintf(buff, 20, "%d", i); + err = std::string(sz) + "\nline " + buff + ", function " + func__ + ", file " + FILE__; +} diff --git a/src/ILog.h b/src/ILog.h index bee8b24..68f11ca 100644 --- a/src/ILog.h +++ b/src/ILog.h @@ -22,6 +22,8 @@ public: 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(const char* sz, int i, const char*, const char*) noexcept; + // usage throw MyException("error", __LINE__, __func__, __FILE__); explicit MyException(int, sqlite3*) noexcept; virtual const char* what() const override { return err.c_str(); diff --git a/src/display_wallet.cpp b/src/display_wallet.cpp index c463245..11a6efa 100644 --- a/src/display_wallet.cpp +++ b/src/display_wallet.cpp @@ -24,6 +24,9 @@ display_wallet::display_wallet(wxWindow* parent, wxFileName& walletfile) : SetSizer(sizer); ro::sql read_keys(m_db, R"|(SELECT * FROM "Keys";)|"); sql_read_name read_name(m_db); //*It would be better to have a select statement goes through the name table, in name order. This is unit test code wrongly repurposed. + /* ro::sql sql_read_names( + m_db, + R"|(SELECT Names.name, Keys.pubkey FROM Names INNER JOIN Keys ON Names.ROWID=Keys.id AND Keys.use=1 ORDER BY Names.name;)|"){} */ // m_db.reset(nullptr);// Force error of premature destruction of Isqlite3 while (read_keys.step() == Icompiled_sql::ROW) { auto pubkey = read_keys.column(1); @@ -106,4 +109,4 @@ void display_wallet::OnClose(wxCloseEvent& event) { // replacing the default handler.' if (singletonFrame->m_panel ==this)singletonFrame->m_panel = nullptr; -} \ No newline at end of file +} diff --git a/src/frame.cpp b/src/frame.cpp index bc031c0..6708f5c 100644 --- a/src/frame.cpp +++ b/src/frame.cpp @@ -256,6 +256,7 @@ CREATE TABLE "Keys"( "use" INTEGER NOT NULL); CREATE UNIQUE INDEX i_pubkey ON Keys (pubkey); +CREATE UNIQUE INDEX i_id ON Keys (use, id); CREATE TABLE "Names"( "ROWID" INTEGER PRIMARY KEY, diff --git a/src/introspection_of_standard_C_types.h b/src/introspection_of_standard_C_types.h index a0146f2..b9c30e6 100644 --- a/src/introspection_of_standard_C_types.h +++ b/src/introspection_of_standard_C_types.h @@ -169,3 +169,8 @@ std::enable_if_t, decltype(std::span(declval())[0] } return retval; } +#pragma warning(disable : 5056) +// This header file turns off deprecation of array type compares, because +// it provides an array spaceship operator that solves the inconsistency +// problem in a better way. Spaceship compares of arrays in my code are +// no longer ill formed. \ No newline at end of file diff --git a/src/stdafx.h b/src/stdafx.h index 0922ea6..098c295 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -62,7 +62,6 @@ 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 && wxVERSION_STRING == wxT("wxWidgets 3.2.0"), "expecting wxWidgets 3.2.0"); 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"); @@ -85,6 +84,11 @@ std::span& operator^=(std::span&, byte *); #pragma comment(lib, "libsodium.lib") inline wxString _wx(const char* sz) { return wxString::FromUTF8Unchecked(sz); } #include "introspection_of_standard_C_types.h" +// This header file turns off deprecation of array type compares, because +// it provides an array spaceship operator that solves the inconsistency +// problem in a better way. Spaceship compares of arrays in my code are +// no longer ill formed. +static_assert(wxMAJOR_VERSION == 3 && wxMINOR_VERSION == 2 && wxRELEASE_NUMBER == 0 && wxSUBRELEASE_NUMBER == 1 && wxVERSION_STRING == wxT("wxWidgets 3.2.0"), "expecting wxWidgets 3.2.0"); #include "rotime.h" #include "slash6.h" #include "ISqlite3.h" diff --git a/src/unit_test.cpp b/src/unit_test.cpp index 69d85cb..9ce7780 100644 --- a/src/unit_test.cpp +++ b/src/unit_test.cpp @@ -1,4 +1,5 @@ #include "stdafx.h" +static constexpr char SrcFilename[]{ "src/unit_test.cpp" }; using ro::msec, ro::msec_since_epoch, ro::bin2hex, ro::to_base64_string, ristretto255::hash, ristretto255::hsh, ristretto255::scalar, ristretto255::point, ro::base58; @@ -68,6 +69,11 @@ static bool EndUnitTest() { throw EndUnitTestOfExceptions(); } catch (const EndUnitTestOfExceptions&) {} + catch (const MyException& e) { + errorCode = e.what_num(); + szError = e.what(); + ILogError(szError.c_str()); + } catch (const std::exception& e) { errorCode = 1001; szError = intestbed + e.what(); @@ -105,7 +111,7 @@ static bool curve_order(void) { mpz_get_str(sz, 16, mpir::ristretto25519_curve_order); wxString curve_order_as_mpir_bigint{ _wx(sz) }; if (curve_order_as_unreduced_scalar != curve_order_as_mpir_bigint){ - throw MyException("inconsistent curve order"); + throw MyException("inconsistent curve order", __LINE__, __func__, SrcFilename); } scalar sc_zero{ 0 }; scalar sc_one{ 1 }; @@ -138,7 +144,12 @@ static bool curve_order(void) { && sc1.valid()) && !scalar::scOrder.valid() && !scalar(0).valid(); - if (!f)throw MyException("scalar range and validation messed up"); + if (!f)throw MyException("scalar range and validation messed up", __LINE__, __func__, SrcFilename); + } + catch (const MyException& e) { + errorCode = e.what_num(); + szError = e.what(); + ILogError(szError.c_str()); } catch (const std::exception& e) { errorCode = 30; @@ -180,14 +191,14 @@ static bool checkDataConversionsProduceExpected(void){ || hash(p_brownfox) != hash(hsh() << ar_brownfox << wx_over.ToUTF8()) || hash(p_brownfox) != hash(ar_brownfox, wx_over.ToUTF8()) || hash(brownfox) != hash(ar_brownfox, p_over) - )throw MyException(sz_inconsistent_hash); + )throw MyException(sz_inconsistent_hash, __LINE__, __func__, SrcFilename); { scalar scl_b{ scalar::random() }; point pt_a{ scl_b.timesBase() }; std::string str_pt_a{ &(base58(pt_a))[0] }; if (pt_a != base58::bin(str_pt_a.c_str())){ - throw MyException("Round trip from and two base 58 representation failed"); + throw MyException("Round trip from and two base 58 representation failed", __LINE__, __func__, SrcFilename); } } { @@ -231,9 +242,14 @@ static bool checkDataConversionsProduceExpected(void){ if (base58(hash_b).operator std::string() != "i22EVNPsKRjdxYTZrPPu9mx6vnrBjosFix5F4gn2mb2kF" ){ - throw MyException("unexpected hash of transformations"); + throw MyException("unexpected hash of transformations", __LINE__, __func__, SrcFilename); } } + catch (const MyException& e) { + errorCode = e.what_num(); + szError = e.what(); + ILogError(szError.c_str()); + } catch (const std::exception& e) { errorCode = 27; szError = e.what(); @@ -277,6 +293,11 @@ static bool CheckForUtfEnvironment(void) { } if (!utfEnvironment) { throw MyException(utfError); } } + catch (const MyException& e) { + errorCode = e.what_num(); + szError = e.what(); + ILogError(szError.c_str()); + } catch (const std::exception& e) { errorCode = 24; szError = e.what(); @@ -386,12 +407,12 @@ static bool OpenWallet(void) { else fWalletNameOk = true; std::unique_ptr db; if (fWalletNameOk) { - if (!LastUsedSqlite.FileExists()) throw MyException("Expected wallet file not found"); + if (!LastUsedSqlite.FileExists()) throw MyException("Expected wallet file not found", __LINE__, __func__, SrcFilename); db.reset(Sqlite3_open(LastUsedSqlite.GetFullPath().ToUTF8())); sql_read_from_misc read_from_misc(db.get()); - if(!read_from_misc(1) || read_from_misc.value() != WALLET_FILE_IDENTIFIER)throw MyException("Unrecognizable wallet file format"); - if(!read_from_misc(2) || read_from_misc.value() != WALLET_FILE_SCHEMA_VERSION_0_0)throw MyException("Unrecognized wallet schema"); - if (!read_from_misc(4)) throw MyException("Mastersecret missing"); + if(!read_from_misc(1) || read_from_misc.value() != WALLET_FILE_IDENTIFIER)throw MyException("Unrecognizable wallet file format", __LINE__, __func__, SrcFilename); + if(!read_from_misc(2) || read_from_misc.value() != WALLET_FILE_SCHEMA_VERSION_0_0)throw MyException("Unrecognized wallet schema", __LINE__, __func__, SrcFilename); + if (!read_from_misc(4)) throw MyException("Mastersecret missing", __LINE__, __func__, SrcFilename); ristretto255::CMasterSecret MasterSecret(*read_from_misc.value()); ro::sql read_keys(db.get(), R"|(SELECT * FROM "Keys" LIMIT 5;)|"); sql_read_name read_name(db.get()); @@ -400,10 +421,10 @@ static bool OpenWallet(void) { auto pubkey = read_keys.column(1); auto id = read_keys.column(2); auto use = read_keys.column(3); - if (use != 1)throw MyException(sz_unknown_secret_key_algorithm); - if (!read_name(id)) throw MyException(sz_no_corresponding_entry); + if (use != 1)throw MyException(sz_unknown_secret_key_algorithm, __LINE__, __func__, SrcFilename); + if (!read_name(id)) throw MyException(sz_no_corresponding_entry, __LINE__, __func__, SrcFilename); const char* name = read_name.name(); - if(MasterSecret(name).timesBase()!=*pubkey)throw MyException(R"|(Public key of name fails to correspond)|"); + if(MasterSecret(name).timesBase()!=*pubkey)throw MyException(R"|(Public key of name fails to correspond)|", __LINE__, __func__, SrcFilename); wxLogMessage(wxT("\t\t\"%s\" has expected public key 0x%s"), name, (wxString)(bin2hex(*pubkey))); } } @@ -428,6 +449,7 @@ CREATE TABLE "Keys"( "use" INTEGER NOT NULL); CREATE UNIQUE INDEX i_pubkey ON Keys (pubkey); +CREATE UNIQUE INDEX i_id ON Keys (use, id); CREATE TABLE "Names"( "ROWID" INTEGER PRIMARY KEY, @@ -470,6 +492,11 @@ COMMIT;)|"); } } // End of wallet creation branch } + catch (const MyException& e) { + errorCode = e.what_num(); + szError = e.what(); + ILogError(szError.c_str()); + } catch (const std::exception & e) { errorCode = 20; szError = e.what(); @@ -516,11 +543,11 @@ namespace ristretto255 { szError = "Fail\tUnexpected text secret from scalar(7)"; ILogError(szError.c_str()); } - if (std::popcount(0x0123456789ABCDEFu) != 0x20)throw MyException(sz_bitcount_incorrect); - if (rounded_log2(0x345678u) != 22) throw MyException(sz_rounded_log2_incorrect); + if (std::popcount(0x0123456789ABCDEFu) != 0x20)throw MyException(sz_bitcount_incorrect, __LINE__, __func__, SrcFilename); + if (rounded_log2(0x345678u) != 22) throw MyException(sz_rounded_log2_incorrect, __LINE__, __func__, SrcFilename); { uint64_t v{ 0x123456789ABCDEFu }; for (unsigned int i = 0; i <= 64; i++) { - if (i != std::countr_zero(v))throw MyException(sz_count_of_trailing_zero_bits_incorrect); + if (i != std::countr_zero(v))throw MyException(sz_count_of_trailing_zero_bits_incorrect, __LINE__, __func__, SrcFilename); v <<= 1; } } @@ -556,6 +583,11 @@ namespace ristretto255 { ILogMessage("\t\tSkipping test of strong secret generation in quick unit test, because strong secret generation is deliberately slow."); } } + catch (const MyException& e) { + errorCode = e.what_num(); + szError = e.what(); + ILogError(szError.c_str()); + } catch (const std::exception & e) { errorCode = 16; szError = e.what(); @@ -573,7 +605,7 @@ namespace ristretto255 { static bool TestShareSecretGenerationSpeed(void) { ILogMessage("\tTest shared secret generation speed."); try { - // throw MyException("fake failure to test failure handling"); + // throw MyException("fake failure to test failure handling", __LINE__, __func__, SrcFilename); unsigned int secrets{ 10 }; scalar a{ scalar::random() }; scalar b{ scalar::random() }; @@ -590,7 +622,8 @@ static bool TestShareSecretGenerationSpeed(void) { B = b * A; } auto end_time{ std::chrono::high_resolution_clock::now() }; - if (!B.valid()) { throw MyException("Unexpected invalid scalar"); } + if (!B.valid()) { throw MyException("Unexpected invalid scalar", __LINE__, __func__, SrcFilename); + } auto time_taken{ std::chrono::duration_cast (end_time - start_time) }; wxLogMessage("\t\t%d shared secrets from public and private keys took %lld microseconds", secrets * 3, time_taken.count()); if (time_taken.count()) { @@ -600,6 +633,11 @@ static bool TestShareSecretGenerationSpeed(void) { ); } } + catch (const MyException& e) { + errorCode = e.what_num(); + szError = e.what(); + ILogError(szError.c_str()); + } catch (const std::exception& e) { errorCode = 23; szError = e.what(); @@ -738,6 +776,11 @@ static bool TestShareSecretGenerationSpeed(void) { wxLogMessage(wxT("\t\tcrypto_shorthash_KEYBYTES\t== %08x"), crypto_shorthash_KEYBYTES); wxLogMessage(wxT("\t\tcrypto_auth_BYTES\t\t== %08x"), crypto_auth_BYTES); } + catch (const MyException& e) { + errorCode = e.what_num(); + szError = e.what(); + ILogError(szError.c_str()); + } catch (const std::exception & e) { errorCode = 15; szError = e.what(); @@ -790,9 +833,9 @@ static bool TestShareSecretGenerationSpeed(void) { auto start_time{ std::chrono::high_resolution_clock::now() }; auto sclr_a = scalar::random(); auto sclr_b = scalar::random(); - if (sclr_a == sclr_b)throw MyException("random not very random"); + if (sclr_a == sclr_b)throw MyException("random not very random", __LINE__, __func__, SrcFilename); auto sclr_c = sclr_a * sclr_b; - if (sclr_b != sclr_c / sclr_a)throw MyException("multiplicative inverse not inverse"); + if (sclr_b != sclr_c / sclr_a)throw MyException("multiplicative inverse not inverse", __LINE__, __func__, SrcFilename); if (false || !scalar::random().valid() || point::ptBase - point::ptBase != point::ptZero @@ -894,13 +937,13 @@ static bool TestShareSecretGenerationSpeed(void) { hash( hsh() << first << second ) - ) throw MyException("inconsistent hashes generated on strings"); + ) throw MyException("inconsistent hashes generated on strings", __LINE__, __func__, SrcFilename); const char* _ = "hello"; hash a(_); hash b(a); hash c(b); if (hash(b, c) != hash(hsh() << b << c) - ) throw MyException("inconsistent hashes generated"); + ) throw MyException("inconsistent hashes generated", __LINE__, __func__, SrcFilename); constexpr int hashes{ 3000 }; start_time = std::chrono::high_resolution_clock::now(); for (int i{ 0 }; i < hashes; i++) { @@ -937,6 +980,11 @@ static bool TestShareSecretGenerationSpeed(void) { } } + catch (const MyException& e) { + errorCode = e.what_num(); + szError = e.what(); + ILogError(szError.c_str()); + } catch (const std::exception & e) { errorCode = 10; szError = e.what(); @@ -1083,6 +1131,11 @@ static bool slash6UnitTest(void) { } // If you touch the slash6 encoding, try retesting with the number of tests tries set to one hundred thousand instead of five, to catch all code paths and weird special cases. } + catch (const MyException& e) { + errorCode = e.what_num(); + szError = e.what(); + ILogError(szError.c_str()); + } catch (const std::exception & e) { errorCode = 12; szError = e.what();