Move wallet creation out of the createwallet rpc into its own function

This commit is contained in:
Andrew Chow 2019-05-24 17:13:13 -04:00
parent 357488f660
commit 1aecdf2063
3 changed files with 82 additions and 46 deletions

View file

@ -2677,17 +2677,12 @@ static UniValue createwallet(const JSONRPCRequest& request)
}, },
}.Check(request); }.Check(request);
std::string error;
std::string warning;
uint64_t flags = 0; uint64_t flags = 0;
if (!request.params[1].isNull() && request.params[1].get_bool()) { if (!request.params[1].isNull() && request.params[1].get_bool()) {
flags |= WALLET_FLAG_DISABLE_PRIVATE_KEYS; flags |= WALLET_FLAG_DISABLE_PRIVATE_KEYS;
} }
bool create_blank = false; // Indicate that the wallet is actually supposed to be blank and not just blank to make it encrypted
if (!request.params[2].isNull() && request.params[2].get_bool()) { if (!request.params[2].isNull() && request.params[2].get_bool()) {
create_blank = true;
flags |= WALLET_FLAG_BLANK_WALLET; flags |= WALLET_FLAG_BLANK_WALLET;
} }
SecureString passphrase; SecureString passphrase;
@ -2698,55 +2693,24 @@ static UniValue createwallet(const JSONRPCRequest& request)
// Empty string is invalid // Empty string is invalid
throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Cannot encrypt a wallet with a blank password"); 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;
} }
if (!request.params[4].isNull() && request.params[4].get_bool()) { if (!request.params[4].isNull() && request.params[4].get_bool()) {
flags |= WALLET_FLAG_AVOID_REUSE; flags |= WALLET_FLAG_AVOID_REUSE;
} }
WalletLocation location(request.params[0].get_str()); std::string error;
if (location.Exists()) { std::string warning;
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet " + location.GetName() + " already exists."); 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");
} }
// Wallet::Verify will check if we're trying to create a wallet with a duplication name.
if (!CWallet::Verify(*g_rpc_interfaces->chain, location, false, error, warning)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet file verification failed: " + error);
}
std::shared_ptr<CWallet> const wallet = CWallet::CreateWalletFromFile(*g_rpc_interfaces->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();
}
}
AddWallet(wallet);
wallet->postInitProcess();
UniValue obj(UniValue::VOBJ); UniValue obj(UniValue::VOBJ);
obj.pushKV("name", wallet->GetName()); obj.pushKV("name", wallet->GetName());
obj.pushKV("warning", warning); obj.pushKV("warning", warning);

View file

@ -160,6 +160,70 @@ std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string&
return LoadWallet(chain, WalletLocation(name), error, warning); 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)
{
// 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(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<CWallet> wallet = CWallet::CreateWalletFromFile(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 uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000;
const uint256 CMerkleTx::ABANDON_HASH(uint256S("0000000000000000000000000000000000000000000000000000000000000001")); const uint256 CMerkleTx::ABANDON_HASH(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));

View file

@ -49,6 +49,14 @@ std::vector<std::shared_ptr<CWallet>> GetWallets();
std::shared_ptr<CWallet> GetWallet(const std::string& name); 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); std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const WalletLocation& location, std::string& error, std::string& warning);
enum 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);
//! Default for -keypool //! Default for -keypool
static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000; static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000;
//! -paytxfee default //! -paytxfee default