Merge branch 'master' of ../../wallet into docs

This commit is contained in:
Cheng 2023-05-16 08:09:44 +08:00
commit 8c07e05a82
No known key found for this signature in database
GPG Key ID: 571C3A9C3B9E6FCA
10 changed files with 74 additions and 41 deletions

View File

@ -8,7 +8,7 @@ In a Git bash command prompt, `cd` to the directory where you intend to
install the source code. install the source code.
```bash ```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 Then launch the visual studio X64 native tools command prompt. `cd` to the

View File

@ -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_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 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 { class MyException: public std::exception {
private: private:
std::string err; std::string err;
int err_number;
public: public:
virtual ~MyException() override = default; virtual ~MyException() override = default;
MyException() = delete; MyException() = delete;
explicit MyException(const std::string &m) noexcept :err(m){} explicit MyException(const std::string &m) noexcept :err(m.c_str()),err_number(-1){}
explicit MyException(const char* sz) noexcept :err(sz) {} 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 { virtual const char* what() const override {
return err.c_str(); return err.c_str();
} }
virtual const int what_num() const {
return err_number;
}
}; };
class FatalException : public MyException { class FatalException : public MyException {
@ -35,12 +43,6 @@ public:
HashReuseException() noexcept; HashReuseException() noexcept;
}; };
class SQLexception : public MyException {
public:
using MyException::MyException;
SQLexception() noexcept;
};
class NonUtf8DataInDatabase : public MyException { class NonUtf8DataInDatabase : public MyException {
public: public:
using MyException::MyException; using MyException::MyException;

View File

@ -24,7 +24,7 @@ void sqlite3_init() {
if (sqlite3_initialize() != SQLITE_OK) { if (sqlite3_initialize() != SQLITE_OK) {
errorCode = 7; errorCode = 7;
szError = "Fatal Error: Sqlite library did not init."; 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()); throw FatalException(szError.c_str());
} }
} }
@ -35,7 +35,7 @@ static int callback(void* NotUsed, int argc, char** argv, char** azColName) {
std::string str; std::string str;
str.reserve(256); str.reserve(256);
for (int i = 0; i < argc; i++) { 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()); ILogMessage(str.c_str());
return 0; return 0;
@ -52,7 +52,7 @@ public:
pdb = nullptr; pdb = nullptr;
#endif #endif
int rc =sqlite3_open_v2(dbName, &pdb, flags, nullptr); 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); assert(pdb != nullptr);
// pdb can never be nullptr, since the sqlite3_open_v2 command always initializes // pdb can never be nullptr, since the sqlite3_open_v2 command always initializes
// it even if open fails // it even if open fails
@ -62,7 +62,7 @@ public:
char* zErrMsg = nullptr; char* zErrMsg = nullptr;
int rc = sqlite3_exec(pdb, szsql, callback, nullptr, &zErrMsg); int rc = sqlite3_exec(pdb, szsql, callback, nullptr, &zErrMsg);
if (rc != SQLITE_OK) { if (rc != SQLITE_OK) {
SQLexception e(std::string("SQL Exec Error: ") + zErrMsg); auto e = MyException(zErrMsg, rc);
sqlite3_free(zErrMsg); sqlite3_free(zErrMsg);
throw e; throw e;
} }
@ -90,6 +90,11 @@ ISqlite3* Sqlite3_open(const char * db_name) {
return new ISqlite3Impl(db_name, SQLITE_OPEN_READWRITE); 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. // Factory method to create database.
ISqlite3 * Sqlite3_create(const char* db_name) { ISqlite3 * Sqlite3_create(const char* db_name) {
return new ISqlite3Impl(db_name, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); return new ISqlite3Impl(db_name, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
@ -101,10 +106,10 @@ class IcompiledImpl_sql :
friend class ISqlite3Impl; friend class ISqlite3Impl;
private: private:
sqlite3_stmt *pStmt; sqlite3_stmt *pStmt;
ISqlite3Impl *pdbImplOwn; ISqlite3Impl*pdbImplOwn;
auto e(int rc) { auto e(int rc) {
assert(rc != SQLITE_OK); assert(rc != SQLITE_OK);
return SQLexception(error_message(rc, pdbImplOwn->pdb)); return MyException(rc, pdbImplOwn->pdb);
} }
public: public:
IcompiledImpl_sql() = delete; 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. // 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 // 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, // 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; break;
case SQLITE_MISUSE: case SQLITE_MISUSE:
//ret = MISUSE; //ret = MISUSE;

View File

@ -114,8 +114,9 @@ namespace ro {
result step() { result step() {
return (*this)->Isqlite3_step(); return (*this)->Isqlite3_step();
} }
void final_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() { void reset() {
(*this)->Isqlite3_reset(); (*this)->Isqlite3_reset();
@ -183,12 +184,15 @@ class sql_insert_name {
ro::sql csql_into_names; ro::sql csql_into_names;
ro::sql csql_namekey_into_keys; ro::sql csql_namekey_into_keys;
ro::sql csql_commit; ro::sql csql_commit;
ro::sql csql_rollback;
public: public:
sql_insert_name(ISqlite3* p) : sql_insert_name(ISqlite3* p) :
csql_begin(p, R"|(BEGIN;)|"), csql_begin(p, R"|(BEGIN IMMEDIATE;)|"),
csql_into_names(p, R"|(INSERT OR ROLLBACK INTO "Names" VALUES(?1);)|"), csql_into_names(p, R"|(INSERT OR FAIL INTO "Names" VALUES(?1);)|"),
csql_namekey_into_keys(p, R"|(INSERT OR ROLLBACK INTO "Keys" VALUES(?1, last_insert_rowid(), 1);)|"), csql_namekey_into_keys(p, R"|(INSERT OR FAIL 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<ISqlite3>& p) : sql_insert_name(p.get()) {} sql_insert_name(const std::unique_ptr<ISqlite3>& p) : sql_insert_name(p.get()) {}
void operator()(const char* psz, const ristretto255::point& pt) { void operator()(const char* psz, const ristretto255::point& pt) {
csql_begin.do_one(); csql_begin.do_one();
@ -196,9 +200,18 @@ public:
csql_into_names.do_one(psz); csql_into_names.do_one(psz);
csql_namekey_into_keys.do_one(pt); csql_namekey_into_keys.do_one(pt);
} }
catch (const std::exception & e) { catch (const MyException& e) {
csql_commit.do_one(); csql_rollback.do_one();
throw e; if (e.what_num() == 19) {
throw MyException("Name already in database");
}
else {
throw;
}
}
catch (const std::exception &) {
csql_rollback.do_one();
throw;
} }
csql_commit.do_one(); csql_commit.do_one();
} }

View File

@ -79,10 +79,10 @@ void display_wallet::close_menu_event_handler(wxCommandEvent& event) {
void display_wallet::add_name_event_handler(wxCommandEvent& event) { void display_wallet::add_name_event_handler(wxCommandEvent& event) {
wxTextEntryDialog dialog(this, wxTextEntryDialog dialog(this,
"This is a small sample\n" R"("A Zooko name has a human readable name,
"A long, long string to test out the text entrybox", and a public key defined by the name and the wallet master secret)",
"Please enter a string", "Create a Zooko name",
"Default value", "",
wxOK | wxCANCEL); wxOK | wxCANCEL);
if (dialog.ShowModal() == wxID_OK) if (dialog.ShowModal() == wxID_OK)
{ {

View File

@ -65,7 +65,7 @@ Frame::Frame(wxString wxs)
m_panel(), m_panel(),
m_LastUsedSqlite() m_LastUsedSqlite()
{ {
try { try {
assert(singletonFrame == nullptr); assert(singletonFrame == nullptr);
singletonFrame = this; singletonFrame = this;
SetIcon(wxICON(AAArho)); SetIcon(wxICON(AAArho));
@ -150,14 +150,29 @@ try {
menuBar->EnableTop(1, false); //disable edit menu. menuBar->EnableTop(1, false); //disable edit menu.
// child controls // child controls
m_LastUsedSqlite.Assign(singletonApp->pConfig->Read(wxT("/Wallet/LastUsed"), wxT(""))); m_LastUsedSqlite.Assign(singletonApp->pConfig->Read(wxT("/Wallet/LastUsed"), wxT("")));
if (!m_LastUsedSqlite.IsOk() || !m_LastUsedSqlite.HasName() || !m_LastUsedSqlite.HasExt()) { wxPanel* panel{ nullptr };
m_panel = new welcome_to_rhocoin(this); //Owner is "this", via the base class wxFrame. m_panel is a try {
// non owning pointer in the derived class that duplicates the owning pointer in the base class. if (m_LastUsedSqlite.IsOk())
{ //Try to load an existing file.
panel = new display_wallet(this, m_LastUsedSqlite);
}
else {
panel = new welcome_to_rhocoin(this);
}
} }
else { catch (const std::exception& e) {
display_wallet* panel = new display_wallet(this, m_LastUsedSqlite); // if the attempt to load an existing wallet file fails,
m_panel = panel; // 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. 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())); this->RestorePositionFromConfig(ClientToWindowSize(m_panel->GetBestSize()));
SetClientSize(GetClientSize()); SetClientSize(GetClientSize());
} }
@ -230,7 +245,7 @@ void Frame::NewWallet(wxFileName& filename, ristretto255::hash<256>& secret) {
db->exec(R"|( db->exec(R"|(
PRAGMA journal_mode = WAL; PRAGMA journal_mode = WAL;
PRAGMA synchronous = 1; PRAGMA synchronous = 1;
BEGIN TRANSACTION; BEGIN IMMEDIATE TRANSACTION;
CREATE TABLE "Keys"( CREATE TABLE "Keys"(
"pubkey" BLOB NOT NULL UNIQUE PRIMARY KEY, "pubkey" BLOB NOT NULL UNIQUE PRIMARY KEY,
"id" integer NOT NULL, "id" integer NOT NULL,

View File

@ -129,8 +129,6 @@ FatalException::FatalException() noexcept :
MyException(R"|(unspecified fatal exception)|") {}; MyException(R"|(unspecified fatal exception)|") {};
HashReuseException::HashReuseException() noexcept : HashReuseException::HashReuseException() noexcept :
MyException(R"|(finalized the same hash constructor twice or more)|") {}; MyException(R"|(finalized the same hash constructor twice or more)|") {};
SQLexception::SQLexception() noexcept :
MyException(R"|(SQL Exception)|") {};
BadDataException::BadDataException() noexcept : BadDataException::BadDataException() noexcept :
MyException(R"|(Bad data exception)|") {}; MyException(R"|(Bad data exception)|") {};
NonUtf8DataInDatabase::NonUtf8DataInDatabase() noexcept : NonUtf8DataInDatabase::NonUtf8DataInDatabase() noexcept :

View File

@ -62,7 +62,7 @@ constexpr bool b_WINDOWS = false;
static_assert(wxUSE_UNSAFE_WXSTRING_CONV == 1, static_assert(wxUSE_UNSAFE_WXSTRING_CONV == 1,
R"(In fully utf environment, (wallet.manifest plus R"(In fully utf environment, (wallet.manifest plus
/utf-8 compile option) all string conversions are safe.)"); /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 && 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(wxUSE_IPV6 == 1, "IP6 unavailable in wxWidgets");
static_assert(WXWIN_COMPATIBILITY_3_0 == 0, "wxWidgets api out of date"); 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"); static_assert(wxUSE_COMPILER_TLS == (b_WINDOWS ? 2 : 1), "out of date workarounds in wxWidgets for windows bugs");

View File

@ -424,7 +424,7 @@ static bool OpenWallet(void) {
db->exec(R"|( db->exec(R"|(
PRAGMA journal_mode = WAL; PRAGMA journal_mode = WAL;
PRAGMA synchronous = 1; PRAGMA synchronous = 1;
BEGIN TRANSACTION; BEGIN IMMEDIATE TRANSACTION;
CREATE TABLE "Keys"( CREATE TABLE "Keys"(
"pubkey" BLOB NOT NULL UNIQUE PRIMARY KEY, "pubkey" BLOB NOT NULL UNIQUE PRIMARY KEY,
"id" integer NOT NULL, "id" integer NOT NULL,

@ -1 +1 @@
Subproject commit 2648eb4da156a751a377cfe96b91faa03e535c10 Subproject commit 02e885c6f079c6e12a632f92cd7cfcceecf0c39b