Skip to content

Commit

Permalink
wallet, rpc: Be able to create and load wallets with encrypted dbs
Browse files Browse the repository at this point in the history
  • Loading branch information
achow101 committed Sep 14, 2023
1 parent 8b75e96 commit f75430c
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 2 deletions.
20 changes: 19 additions & 1 deletion src/wallet/rpc/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ static RPCHelpMan loadwallet()
{
{"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet directory or .dat file."},
{"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
{"db_passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Passphrase for the wallet database if the database is encrypted"},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
Expand Down Expand Up @@ -244,6 +245,11 @@ static RPCHelpMan loadwallet()
std::vector<bilingual_str> warnings;
std::optional<bool> load_on_start = request.params[1].isNull() ? std::nullopt : std::optional<bool>(request.params[1].get_bool());

options.db_passphrase.reserve(100);
if (!request.params[2].isNull()) {
options.db_passphrase = std::string_view{request.params[2].get_str()};
}

{
LOCK(context.wallets_mutex);
if (std::any_of(context.wallets.begin(), context.wallets.end(), [&name](const auto& wallet) { return wallet->GetName() == name; })) {
Expand Down Expand Up @@ -340,13 +346,14 @@ static RPCHelpMan createwallet()
{"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name for the new wallet. If this is a path, the wallet will be created at the path location."},
{"disable_private_keys", RPCArg::Type::BOOL, RPCArg::Default{false}, "Disable the possibility of private keys (only watchonlys are possible in this mode)."},
{"blank", RPCArg::Type::BOOL, RPCArg::Default{false}, "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."},
{"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Encrypt the wallet with this passphrase."},
{"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Encrypt the keys stored in this wallet with this passphrase."},
{"avoid_reuse", RPCArg::Type::BOOL, RPCArg::Default{false}, "Keep track of coin reuse, and treat dirty and clean coins differently with privacy considerations in mind."},
{"descriptors", RPCArg::Type::BOOL, RPCArg::Default{true}, "Create a native descriptor wallet. The wallet will use descriptors internally to handle address creation."
" Setting to \"false\" will create a legacy wallet; however, the legacy wallet type is being deprecated and"
" support for creating and opening legacy wallets will be removed in the future."},
{"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
{"external_signer", RPCArg::Type::BOOL, RPCArg::Default{false}, "Use an external signer such as a hardware wallet. Requires -signer to be configured. Wallet creation will fail if keys cannot be fetched. Requires disable_private_keys and descriptors set to true."},
{"db_passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Encrypt the entire wallet database with this passphrase."},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
Expand Down Expand Up @@ -409,12 +416,23 @@ static RPCHelpMan createwallet()
}
#endif

SecureString db_passphrase;
db_passphrase.reserve(100);
if (!request.params[8].isNull()) {
db_passphrase = std::string_view{request.params[8].get_str()};
if (db_passphrase.empty()) {
// Empty string means unencrypted
warnings.emplace_back(Untranslated("Empty string given as database passphrase, wallet database will not be encrypted."));
}
}

DatabaseOptions options;
DatabaseStatus status;
ReadDatabaseArgs(*context.args, options);
options.require_create = true;
options.create_flags = flags;
options.create_passphrase = passphrase;
options.db_passphrase = db_passphrase;
bilingual_str error;
std::optional<bool> load_on_start = request.params[6].isNull() ? std::nullopt : std::optional<bool>(request.params[6].get_bool());
const std::shared_ptr<CWallet> wallet = CreateWallet(context, request.params[0].get_str(), load_on_start, options, status, error, warnings);
Expand Down
12 changes: 11 additions & 1 deletion src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,17 @@ std::shared_ptr<CWallet> CreateWallet(WalletContext& context, const std::string&
uint64_t wallet_creation_flags = options.create_flags;
const SecureString& passphrase = options.create_passphrase;

if (wallet_creation_flags & WALLET_FLAG_DESCRIPTORS) options.require_format = DatabaseFormat::SQLITE;
if (wallet_creation_flags & WALLET_FLAG_DESCRIPTORS) {
if (!options.db_passphrase.empty()) {
options.require_format = DatabaseFormat::ENCRYPTED_SQLITE;
} else {
options.require_format = DatabaseFormat::SQLITE;
}
} else if (!options.db_passphrase.empty()) {
error = Untranslated("Database encryption is only supported for descriptor wallets");
status = DatabaseStatus::FAILED_CREATE;
return nullptr;
}

// Indicate that the wallet is actually supposed to be blank and not just blank to make it encrypted
bool create_blank = (wallet_creation_flags & WALLET_FLAG_BLANK_WALLET);
Expand Down

0 comments on commit f75430c

Please sign in to comment.