Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use single instance of CWalletDB in CSparkWallet #1239

Open
wants to merge 12 commits into
base: master
Choose a base branch
from

Conversation

psolstice
Copy link
Contributor

@psolstice psolstice commented May 13, 2023

PR intention

Performance optimization by using single instance of CWalletDB

Code changes brief

This is a first step in a refactor that strongly binds CWallet/CSparkWalletandCWalletDB` together

Summary by CodeRabbit

  • New Features

    • Enhanced support for handling multiple wallets, improving user flexibility and management of different wallets.
    • Streamlined wallet operations, including initialization, shutdown, and database recovery, for better performance and reliability.
    • Added new verification functions for wallet databases, ensuring integrity and security.
  • Refactor

    • Updated wallet handling logic to accommodate multiple wallets seamlessly.
    • Simplified database interactions in wallet functions, reducing redundancy and enhancing efficiency.
    • Refactored wallet database code to improve transaction control and data writing/erasing processes.
  • Bug Fixes

    • Fixed issues in wallet shutdown process to ensure clean wallet closure and data preservation.
    • Addressed wallet database recovery procedures to handle potential errors more effectively.
  • Documentation

    • Updated internal documentation to reflect changes in wallet handling and database operations.

@reubenyap reubenyap requested review from levonpetrosyan93 and a user May 13, 2023 11:03
@levonpetrosyan93 levonpetrosyan93 changed the base branch from spark_second_iteration to spark_ May 19, 2023 23:16
@levonpetrosyan93 levonpetrosyan93 changed the base branch from spark_ to spark_second_iteration May 19, 2023 23:17
@levonpetrosyan93
Copy link
Contributor

@psolstice Please rebase onto spark_ branch

@psolstice psolstice changed the base branch from spark_second_iteration to spark May 22, 2023 13:33
@psolstice psolstice marked this pull request as draft July 24, 2023 08:21
Base automatically changed from spark to master November 23, 2023 19:24
@levoncrypto levoncrypto marked this pull request as ready for review April 6, 2024 05:00
Copy link

coderabbitai bot commented Apr 6, 2024

Walkthrough

The recent updates focus on enhancing wallet management and database recovery within a cryptocurrency framework. Key changes include support for multiple wallets, streamlined wallet database operations, and improved error handling. The modifications span across initialization, shutdown processes, and wallet interaction mechanisms, aiming to refine the system's robustness and efficiency.

Changes

Files Change Summary
src/init.cpp, src/qt/bitcoin.cpp, src/wallet/rpcwallet.cpp, src/wallet/test/..., src/wallet/wallet.cpp, src/wallet/wallet.h Enhanced support for multiple wallets, including adjustments in wallet initialization, shutdown, and RPC interactions.
src/spark/sparkwallet.cpp, src/spark/sparkwallet.h Refactored CSparkWallet, improved database operation efficiency by eliminating redundant operations, and updated function signatures.
src/util.cpp, src/wallet/db.cpp, src/wallet/db.h, src/wallet/walletdb.cpp, src/wallet/walletdb.h Improved database recovery and verification processes, added functionality for environment and file verification, and updated data writing and erasing methods to include update counter incrementation.

Poem

In the realm of code, where changes abound,
A rabbit hopped in, leaving footprints on the ground.
With a flick and a hop, wallets multiple it sought,
Streamlining the data, with efficiency it brought.
🐇💾 Through bits and through bytes, it danced with delight,
"To improve and refine," it whispered to the night.
So here's to the changes, may they make systems bright!

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share

Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/coderabbit-overrides.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

Actionable comments outside the diff hunks (9)
src/wallet/walletdb.cpp (1)

Line range hint 11-18: Consider encapsulating the nWalletDBUpdateCounter increment logic in a separate function or using RAII to ensure consistency and reduce code duplication.

+ void IncrementWalletDBUpdateCounter() {
+     nWalletDBUpdateCounter++;
+ }

Then replace direct increments with calls to this function.

src/init.cpp (8)

Line range hint 10-10:
The handling of the -litemode argument is correctly implemented.


Line range hint 10-10:
The handling of the -znode argument and the associated logic to disable Dandelion for Znodes is correctly implemented.


Line range hint 10-10:
The initialization and validation of the Znode BLS private key are correctly implemented.


Line range hint 10-10:
The handling of the -torsetup argument and the configuration of network settings based on its value are correctly implemented.


Line range hint 10-10:
The initialization and configuration of networking components, including the connection manager and peer logic, are correctly implemented.


Line range hint 10-10:
The creation of the block import thread and the synchronization on the processing of the genesis block are correctly implemented.


Line range hint 10-10:
The initialization of ZMQ notifications and the scheduling of Dash-specific tasks are correctly implemented.


Line range hint 10-10:
The final steps of the initialization process, including wallet loading and data directory maintenance, are correctly implemented.

Review Status

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 9b4e7ef and e4c0237.
Files selected for processing (14)
  • src/init.cpp (4 hunks)
  • src/qt/bitcoin.cpp (1 hunks)
  • src/spark/sparkwallet.cpp (14 hunks)
  • src/spark/sparkwallet.h (5 hunks)
  • src/util.cpp (1 hunks)
  • src/wallet/db.cpp (3 hunks)
  • src/wallet/db.h (3 hunks)
  • src/wallet/rpcwallet.cpp (3 hunks)
  • src/wallet/test/wallet_test_fixture.cpp (1 hunks)
  • src/wallet/test/wallet_tests.cpp (7 hunks)
  • src/wallet/wallet.cpp (8 hunks)
  • src/wallet/wallet.h (4 hunks)
  • src/wallet/walletdb.cpp (10 hunks)
  • src/wallet/walletdb.h (5 hunks)
Files not reviewed due to errors (1)
  • (no review received)
Additional comments not posted (41)
src/spark/sparkwallet.h (3)

24-24: LGTM! The change in parameter type is purely stylistic and does not affect functionality.


31-33: The removal of CWalletDB parameters from functions and the introduction of a CWalletDB walletdb member align with the PR's objectives to optimize database interactions.

Also applies to: 48-48, 65-70, 90-90


139-139: Replacing the strWalletFile member with a CWalletDB walletdb instance centralizes database interactions within CSparkWallet, supporting the PR's goal of optimizing wallet performance.

src/wallet/db.h (4)

59-59: The addition of the recoverFunc_type typedef improves code readability and maintainability by providing a clear definition for the recovery function signature.


60-60: Modifying the Verify method to take the recoverFunc_type typedef and an additional out_backup_filename parameter enhances its functionality.


94-142: The introduction of the CWalletDBWrapper class with methods for database handling likely improves code organization and facilitates easier management of database interactions.


161-169: Additions to the CDB class enhance its database management capabilities by providing methods for database recovery, periodic flushing, environment verification, and database file verification.

src/wallet/walletdb.h (5)

189-208: The addition of WriteIC and EraseIC private template functions encapsulates common patterns of writing/erasing and incrementing the update counter, enhancing code reuse and maintainability.


211-213: Modifying the CWalletDB constructor to take a CWalletDBWrapper reference and initialize batch and m_dbw improves the constructor's functionality by enhancing database operation management.


285-299: Updates to method signatures for functions like FindWalletTx, ZapWalletTx, ZapSelectTx, and others align with the changes in database interaction patterns introduced by the CWalletDBWrapper and the new transaction control methods.


471-479: The addition of transaction control methods TxnBegin, TxnCommit, and TxnAbort to CWalletDB enhances the robustness and flexibility of database operations.


481-482: The introduction of batch and m_dbw as private members in CWalletDB facilitates more efficient and organized management of database operations and interactions with the CWalletDBWrapper.

src/wallet/db.cpp (3)

143-149: > 📝 NOTE

This review was outside the diff hunks and was mapped to the diff hunk with the greatest overlap. Original lines [146-159]

Consider adding a brief comment explaining the purpose and expected behavior of the recoverFunc_type parameter for future maintainability.


163-228: Ensure proper error handling and logging for file operations (rename, open) to handle potential failures gracefully.


435-438: LGTM!

src/wallet/test/wallet_tests.cpp (2)

407-407: The replacement of ::pwalletMain = &wallet; with vpwallets.insert(vpwallets.begin(), &wallet); aligns with the objective of supporting multiple wallets. Consider adding a comment explaining why vpwallets.begin() is chosen for insertion to aid future maintainability.

Also applies to: 477-477, 492-492, 505-505


429-437: The updates to BOOST_CHECK_EQUAL comparisons in test cases are correctly implemented to reflect the changes in wallet handling.

src/qt/bitcoin.cpp (1)

483-486: Consider enhancing the GUI to fully support multiple wallets in the future. The current implementation only exposes the first wallet in vpwallets to the GUI.

src/wallet/walletdb.cpp (5)

100-112: > 📝 NOTE

This review was outside the diff hunks and was mapped to the diff hunk with the greatest overlap. Original lines [83-109]

Ensure that sensitive data, such as private keys, is securely handled and erased from memory after use to prevent potential security vulnerabilities.


1111-1136: Verify that the atomic operation fOneThread.exchange(true) and the subsequent checks provide the intended thread-safety and performance characteristics for database flushing.


1259-1268: Ensure that the database recovery process is thoroughly tested, especially the callback mechanism in Recover to handle different types of data recovery scenarios.


1360-1363: Confirm that serialization and deserialization processes across the wallet database operations handle all edge cases and data types correctly to prevent data corruption.


100-112: > 📝 NOTE

This review was outside the diff hunks and was mapped to the diff hunk with the greatest overlap. Original lines [83-109]

For functions dealing with critical wallet data, such as mnemonics and mint counts, ensure that error handling is robust and that any failures in these operations are appropriately managed to prevent data loss or corruption.

Also applies to: 132-143, 616-618

src/spark/sparkwallet.cpp (7)

16-16: The constructor initializes a thread pool without checking if the wallet database operations were successful. Ensure that resources are only allocated if initial checks pass.


65-65: Ensure that the explicit type casting to ParallelOpThreadPool<void>* in the destructor is safe and necessary. Consider using static_cast for clarity if the cast is indeed required.


65-65: Ensure that locking cs_spark_wallet in balance calculation methods like getAvailableBalance and getUnconfirmedBalance is sufficient for thread safety and consider potential performance implications of locking in high-frequency operations.


172-172: Verify that the updatetDiversifierInDB method is called at the appropriate times when generating new addresses to ensure the diversifier is consistently updated in the database.


497-497: Ensure that fee calculation in CreateSparkSpendTransaction accurately accounts for all transaction components and adheres to network requirements to prevent transaction rejection.


497-497: Review the coin selection logic in SelectSparkCoins to ensure it efficiently selects coins, minimizing the change and the number of inputs used, which can impact transaction fees and privacy.


497-497: Ensure that GetAvailableSparkCoins correctly filters coins based on spendability and coin control selections, avoiding the inclusion of coins that should not be spent.

src/wallet/rpcwallet.cpp (2)

3471-3471: The removal of walletdb as a parameter in updateMint calls aligns with the PR's objectives and should simplify database interactions.

Please verify the impact of this change on performance and ensure that it meets the expected improvements.


3502-3502: The consistency in removing walletdb as a parameter in updateMint calls across different functions supports the PR's goal of optimizing database interactions.

Please ensure that this change contributes positively to the performance as intended.

src/wallet/wallet.cpp (9)

63-63: Consider encapsulating the global variables into a singleton or a namespace to improve code organization and reduce global namespace pollution.


636-636: The update to plural form in the initialization message is appropriate given the support for multiple wallets.


638-665: Ensure that the error messages and conditions are clear and user-friendly, especially when dealing with file paths and wallet file verification. Consider abstracting some of this logic into helper functions for better readability and maintainability.


5994-5996: Verify that pwalletdb->WriteAccountingEntry properly handles the incremented nAccountingEntryNumber to ensure data consistency. Also, consider error handling for the push back operation to laccentries.


7024-7024: Incrementing the update counter after scanning for wallet transactions and setting the best chain is a good practice for maintaining database consistency. Ensure that IncrementUpdateCounter is thread-safe if concurrent access is possible.


7092-7097: The loop for creating wallets from files specified in -wallet arguments is clear. Ensure that CreateWalletFromFile handles all possible error conditions and that the failure to create a wallet is communicated clearly to the user.


7119-7121: Setting a default wallet file and determining if multiwallet is enabled based on the number of -wallet arguments is a straightforward approach. Ensure that the default behavior aligns with user expectations and documentation.


7130-7150: The parameter interaction logic correctly identifies conflicts and limitations when using certain flags with multiwallet. Ensure that these restrictions are documented and communicated to the user to avoid confusion.


7652-7652: Updating the mint state with spark coins is specific to the wallet's functionality. Ensure that UpdateMintState properly handles all edge cases and that the coins are validated before being added to the wallet.

Comment on lines +46 to +47
// TODO: Some way to access secondary wallets
return vpwallets.empty() ? nullptr : vpwallets[0];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider implementing a more robust solution for selecting wallets in GetWalletForJSONRPCRequest to support scenarios involving multiple wallets.

Would you like me to help design or implement this feature?

Comment on lines +468 to +469
mapMultiArgs[strArg].clear();
mapMultiArgs[strArg].push_back(strValue);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using mapMultiArgs[strArg] = {strValue}; for clarity and efficiency.

-    mapMultiArgs[strArg].clear();
-    mapMultiArgs[strArg].push_back(strValue);
+    mapMultiArgs[strArg] = {strValue};

This refactoring simplifies the code by directly setting the vector to contain the single strValue, which is the intended outcome of clearing and then pushing back the value. It's more concise and potentially more efficient by avoiding the separate clear and push operations.


Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
mapMultiArgs[strArg].clear();
mapMultiArgs[strArg].push_back(strValue);
mapMultiArgs[strArg] = {strValue};

Comment on lines +1360 to +1363
bool CWalletDB::VerifyDatabaseFile(const std::string& walletFile, const fs::path& dataDir, std::string& warningStr, std::string& errorStr)
{
return CDB::VerifyDatabaseFile(walletFile, dataDir, warningStr, errorStr, CWalletDB::Recover);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the newly added BIP47 functionality, ensure that all new database operations are accompanied by comprehensive unit tests to verify correctness, especially given the complexity of BIP47 payment codes and privacy implications.

Would you like me to help generate unit tests for the BIP47 related database operations?

Comment on lines +230 to +286
bool CDB::VerifyEnvironment(const std::string& walletFile, const fs::path& dataDir, std::string& errorStr)
{
LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0));
LogPrintf("Using wallet %s\n", walletFile);

// Wallet file must be a plain filename without a directory
if (walletFile != fs::basename(walletFile) + fs::extension(walletFile))
{
errorStr = strprintf(_("Wallet %s resides outside data directory %s"), walletFile, dataDir.string());
return false;
}

if (!bitdb.Open(dataDir))
{
// try moving the database env out of the way
fs::path pathDatabase = dataDir / "database";
fs::path pathDatabaseBak = dataDir / strprintf("database.%d.bak", GetTime());
try {
fs::rename(pathDatabase, pathDatabaseBak);
LogPrintf("Moved old %s to %s. Retrying.\n", pathDatabase.string(), pathDatabaseBak.string());
} catch (const fs::filesystem_error&) {
// failure is ok (well, not really, but it's not worse than what we started with)
}

// try again
if (!bitdb.Open(dataDir)) {
// if it still fails, it probably means we can't even create the database env
errorStr = strprintf(_("Error initializing wallet database environment %s!"), GetDataDir());
return false;
}
}
return true;
}

bool CDB::VerifyDatabaseFile(const std::string& walletFile, const fs::path& dataDir, std::string& warningStr, std::string& errorStr, CDBEnv::recoverFunc_type recoverFunc)
{
if (fs::exists(dataDir / walletFile))
{
std::string backup_filename;
CDBEnv::VerifyResult r = bitdb.Verify(walletFile, recoverFunc, backup_filename);
if (r == CDBEnv::RECOVER_OK)
{
warningStr = strprintf(_("Warning: Wallet file corrupt, data salvaged!"
" Original %s saved as %s in %s; if"
" your balance or transactions are incorrect you should"
" restore from a backup."),
walletFile, backup_filename, dataDir);
}
if (r == CDBEnv::RECOVER_FAIL)
{
errorStr = strprintf(_("%s corrupt, salvage failed"), walletFile);
return false;
}
}
// also return true if files does not exists
return true;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding unit tests for CDB::VerifyEnvironment and CDB::VerifyDatabaseFile to ensure their functionality is correctly implemented and to catch any future regressions.

Would you like me to help with drafting these unit tests?

@@ -18,6 +18,8 @@
#include <boost/test/unit_test.hpp>
#include <univalue.h>

extern CWallet* pwalletMain;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the unnecessary extern CWallet* pwalletMain; declaration, as the code is moving away from using a global pwalletMain in favor of vpwallets.

CWalletDB walletdb(strWalletFile);
this->strWalletFile = strWalletFile;

CSparkWallet::CSparkWallet(const std::string &strWalletFile) : walletdb(strWalletFile) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider handling the case where walletdb initialization fails.

walletdb.readDiversifier(lastDiversifier);
}

void CSparkWallet::updatetDiversifierInDB(CWalletDB& walletdb) {
void CSparkWallet::updatetDiversifierInDB() {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix the typo in the method name updatetDiversifierInDB to updateDiversifierInDB.

- void CSparkWallet::updatetDiversifierInDB() {
+ void CSparkWallet::updateDiversifierInDB() {

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
void CSparkWallet::updatetDiversifierInDB() {
void CSparkWallet::updateDiversifierInDB() {

@@ -502,7 +494,7 @@ CAmount CSparkWallet::getMySpendAmount(const std::vector<GroupElement>& lTags) c
return result;
}

void CSparkWallet::UpdateMintState(const std::vector<spark::Coin>& coins, const uint256& txHash, CWalletDB& walletdb) {
void CSparkWallet::UpdateMintState(const std::vector<spark::Coin>& coins, const uint256& txHash) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider refactoring CreateSparkSpendTransaction to improve readability and maintainability. The method is complex and handles multiple responsibilities, which could be separated into smaller, more focused functions.

@@ -8,6 +8,8 @@
#include "wallet/db.h"
#include "wallet/wallet.h"

CWallet *pwalletMain;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initialize the global variable pwalletMain to null to avoid potential undefined behavior.

- CWallet *pwalletMain;
+ CWallet *pwalletMain = nullptr;

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
CWallet *pwalletMain;
CWallet *pwalletMain = nullptr;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: In Progress
Development

Successfully merging this pull request may close these issues.

3 participants