merge bitcoin#16399: Improve wallet creation

This commit is contained in:
Kittywhiskers Van Gogh 2019-07-10 15:44:26 -04:00
parent a0bf4338a1
commit 6fbedf7740
4 changed files with 29 additions and 23 deletions

View File

@ -2783,14 +2783,16 @@ static UniValue createwallet(const JSONRPCRequest& request)
std::string error;
std::string warning;
WalletCreationStatus status;
std::shared_ptr<CWallet> wallet = CreateWallet(*g_rpc_interfaces->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");
std::shared_ptr<CWallet> wallet;
WalletCreationStatus status = CreateWallet(*g_rpc_interfaces->chain, passphrase, flags, request.params[0].get_str(), error, warning, wallet);
switch (status) {
case WalletCreationStatus::CREATION_FAILED:
throw JSONRPCError(RPC_WALLET_ERROR, error);
case WalletCreationStatus::ENCRYPTION_FAILED:
throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, error);
case WalletCreationStatus::SUCCESS:
break;
// no default case, so the compiler can warn about missing cases
}
UniValue obj(UniValue::VOBJ);

View File

@ -171,7 +171,7 @@ std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string&
return LoadWallet(chain, WalletLocation(name), error, warning);
}
std::shared_ptr<CWallet> CreateWallet(interfaces::Chain& chain, const std::string& name, std::string& error, std::string& warning, WalletCreationStatus& status, const SecureString& passphrase, uint64_t wallet_creation_flags)
WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, std::string& error, std::string& warning, std::shared_ptr<CWallet>& result)
{
// 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);
@ -185,39 +185,40 @@ std::shared_ptr<CWallet> CreateWallet(interfaces::Chain& chain, const std::strin
WalletLocation location(name);
if (location.Exists()) {
error = "Wallet " + location.GetName() + " already exists.";
status = WalletCreationStatus::CREATION_FAILED;
return nullptr;
return WalletCreationStatus::CREATION_FAILED;
}
// Wallet::Verify will check if we're trying to create a wallet with a duplicate name.
std::string wallet_error;
if (!CWallet::Verify(chain, location, wallet_error, warning)) {
error = "Wallet file verification failed: " + wallet_error;
status = WalletCreationStatus::CREATION_FAILED;
return nullptr;
return WalletCreationStatus::CREATION_FAILED;
}
// Do not allow a passphrase when private keys are disabled
if (!passphrase.empty() && (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
error = "Passphrase provided but private keys are disabled. A passphrase is only used to encrypt private keys, so cannot be used for wallets with private keys disabled.";
return WalletCreationStatus::CREATION_FAILED;
}
// Make the wallet
std::shared_ptr<CWallet> wallet = CWallet::CreateWalletFromFile(chain, location, wallet_creation_flags);
if (!wallet) {
error = "Wallet creation failed";
status = WalletCreationStatus::CREATION_FAILED;
return nullptr;
return WalletCreationStatus::CREATION_FAILED;
}
// 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;
return WalletCreationStatus::ENCRYPTION_FAILED;
}
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;
return WalletCreationStatus::ENCRYPTION_FAILED;
}
// Set a HD chain for the wallet
@ -237,8 +238,8 @@ std::shared_ptr<CWallet> CreateWallet(interfaces::Chain& chain, const std::strin
}
AddWallet(wallet);
wallet->postInitProcess();
status = WalletCreationStatus::SUCCESS;
return wallet;
result = wallet;
return WalletCreationStatus::SUCCESS;
}
const uint256 CWalletTx::ABANDON_HASH(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));

View File

@ -52,13 +52,13 @@ std::vector<std::shared_ptr<CWallet>> GetWallets();
std::shared_ptr<CWallet> GetWallet(const std::string& name);
std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const WalletLocation& location, std::string& error, std::string& warning);
enum WalletCreationStatus {
enum class WalletCreationStatus {
SUCCESS,
CREATION_FAILED,
ENCRYPTION_FAILED
};
std::shared_ptr<CWallet> CreateWallet(interfaces::Chain& chain, const std::string& name, std::string& error, std::string& warning, WalletCreationStatus& status, const SecureString& passphrase, uint64_t wallet_creation_flags);
WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, std::string& error, std::string& warning, std::shared_ptr<CWallet>& result);
static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000;
//! -paytxfee default

View File

@ -121,5 +121,8 @@ class CreateWalletTest(BitcoinTestFramework):
# Empty passphrase, error
assert_raises_rpc_error(-16, 'Cannot encrypt a wallet with a blank password', self.nodes[0].createwallet, 'w7', False, False, '')
self.log.info('Using a passphrase with private keys disabled returns error')
assert_raises_rpc_error(-4, 'Passphrase provided but private keys are disabled. A passphrase is only used to encrypt private keys, so cannot be used for wallets with private keys disabled.', self.nodes[0].createwallet, wallet_name='w8', disable_private_keys=True, passphrase='thisisapassphrase')
if __name__ == '__main__':
CreateWalletTest().main()