diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3141,22 +3141,12 @@ throw std::runtime_error(help.ToString()); } - const CChainParams &chainParams = config.GetChainParams(); - - std::string error; - std::string warning; - uint64_t flags = 0; if (!request.params[1].isNull() && request.params[1].get_bool()) { flags |= WALLET_FLAG_DISABLE_PRIVATE_KEYS; } - // Indicate that the wallet is actually supposed to be blank and not just - // blank to make it encrypted - bool create_blank = false; - if (!request.params[2].isNull() && request.params[2].get_bool()) { - create_blank = true; flags |= WALLET_FLAG_BLANK_WALLET; } SecureString passphrase; @@ -3168,60 +3158,22 @@ throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Cannot encrypt a wallet with a blank password"); } - // Born encrypted wallets need to be blank first so that wallet creation - // doesn't make any unencrypted keys - flags |= WALLET_FLAG_BLANK_WALLET; - } - - WalletLocation location(request.params[0].get_str()); - if (location.Exists()) { - throw JSONRPCError(RPC_WALLET_ERROR, - "Wallet " + location.GetName() + " already exists."); - } - - // Wallet::Verify will check if we're trying to create a wallet with a - // duplicate name. - if (!CWallet::Verify(chainParams, *g_rpc_node->chain, location, false, - error, warning)) { - throw JSONRPCError(RPC_WALLET_ERROR, - "Wallet file verification failed: " + error); - } - - std::shared_ptr const wallet = CWallet::CreateWalletFromFile( - chainParams, *g_rpc_node->chain, location, flags); - if (!wallet) { - throw JSONRPCError(RPC_WALLET_ERROR, "Wallet creation failed."); } - // Encrypt the wallet if there's a passphrase - if (!passphrase.empty() && !(flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { - if (!wallet->EncryptWallet(passphrase)) { - throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, - "Error: Wallet created but failed to encrypt."); - } - - if (!create_blank) { - // Unlock the wallet - if (!wallet->Unlock(passphrase)) { - throw JSONRPCError( - RPC_WALLET_ENCRYPTION_FAILED, - "Error: Wallet was encrypted but could not be unlocked"); - } - - // Set a seed for the wallet - CPubKey master_pub_key = wallet->GenerateNewSeed(); - wallet->SetHDSeed(master_pub_key); - wallet->NewKeyPool(); - - // Relock the wallet - wallet->Lock(); - } + std::string error; + std::string warning; + WalletCreationStatus status; + std::shared_ptr wallet = CreateWallet( + config.GetChainParams(), *g_rpc_node->chain, + request.params[0].get_str(), error, warning, status, passphrase, flags); + if (status == WalletCreationStatus::CREATION_FAILED) { + throw JSONRPCError(RPC_WALLET_ERROR, error); + } else if (status == WalletCreationStatus::ENCRYPTION_FAILED) { + throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, error); + } else if (status != WalletCreationStatus::SUCCESS) { + throw JSONRPCError(RPC_WALLET_ERROR, "Wallet creation failed"); } - AddWallet(wallet); - - wallet->postInitProcess(); - UniValue obj(UniValue::VOBJ); obj.pushKV("name", wallet->GetName()); obj.pushKV("warning", warning); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -54,6 +54,14 @@ const WalletLocation &location, std::string &error, std::string &warning); +enum class WalletCreationStatus { SUCCESS, CREATION_FAILED, ENCRYPTION_FAILED }; + +std::shared_ptr +CreateWallet(const CChainParams ¶ms, interfaces::Chain &chain, + const std::string &name, std::string &error, std::string &warning, + WalletCreationStatus &status, const SecureString &passphrase, + uint64_t wallet_creation_flags); + //! Default for -keypool static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000; //! -paytxfee default diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -176,6 +176,78 @@ return LoadWallet(chainParams, chain, WalletLocation(name), error, warning); } +std::shared_ptr +CreateWallet(const CChainParams ¶ms, interfaces::Chain &chain, + const std::string &name, std::string &error, std::string &warning, + WalletCreationStatus &status, const SecureString &passphrase, + uint64_t wallet_creation_flags) { + // 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); + + // Born encrypted wallets need to be created blank first. + if (!passphrase.empty()) { + wallet_creation_flags |= WALLET_FLAG_BLANK_WALLET; + } + + // Check the wallet file location + WalletLocation location(name); + if (location.Exists()) { + error = "Wallet " + location.GetName() + " already exists."; + status = WalletCreationStatus::CREATION_FAILED; + return nullptr; + } + + // Wallet::Verify will check if we're trying to create a wallet with a + // duplicate name. + std::string wallet_error; + if (!CWallet::Verify(params, chain, location, false, wallet_error, + warning)) { + error = "Wallet file verification failed: " + wallet_error; + status = WalletCreationStatus::CREATION_FAILED; + return nullptr; + } + + // Make the wallet + std::shared_ptr wallet = CWallet::CreateWalletFromFile( + params, chain, location, wallet_creation_flags); + if (!wallet) { + error = "Wallet creation failed"; + status = WalletCreationStatus::CREATION_FAILED; + return nullptr; + } + + // Encrypt the wallet + if (!passphrase.empty() && + !(wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { + if (!wallet->EncryptWallet(passphrase)) { + error = "Error: Wallet created but failed to encrypt."; + status = WalletCreationStatus::ENCRYPTION_FAILED; + return nullptr; + } + if (!create_blank) { + // Unlock the wallet + if (!wallet->Unlock(passphrase)) { + error = "Error: Wallet was encrypted but could not be unlocked"; + status = WalletCreationStatus::ENCRYPTION_FAILED; + return nullptr; + } + + // Set a seed for the wallet + CPubKey master_pub_key = wallet->GenerateNewSeed(); + wallet->SetHDSeed(master_pub_key); + wallet->NewKeyPool(); + + // Relock the wallet + wallet->Lock(); + } + } + AddWallet(wallet); + wallet->postInitProcess(); + status = WalletCreationStatus::SUCCESS; + return wallet; +} + const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000; const BlockHash CMerkleTx::ABANDON_HASH(uint256S(