mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-19 13:27:35 +02:00
Merge 56d47e19ed into merged_master (Bitcoin PR #19619)
This commit is contained in:
commit
d4e8eb56b0
30 changed files with 291 additions and 270 deletions
|
|
@ -33,7 +33,7 @@ static void CoinSelection(benchmark::Bench& bench)
|
|||
{
|
||||
NodeContext node;
|
||||
auto chain = interfaces::MakeChain(node);
|
||||
CWallet wallet(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
CWallet wallet(chain.get(), "", CreateDummyWalletDatabase());
|
||||
wallet.SetupLegacyScriptPubKeyMan();
|
||||
std::vector<std::unique_ptr<CWalletTx>> wtxs;
|
||||
LOCK(wallet.cs_wallet);
|
||||
|
|
@ -78,7 +78,7 @@ static void CoinSelection(benchmark::Bench& bench)
|
|||
typedef std::set<CInputCoin> CoinSet;
|
||||
static NodeContext testNode;
|
||||
static auto testChain = interfaces::MakeChain(testNode);
|
||||
static CWallet testWallet(testChain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
static CWallet testWallet(testChain.get(), "", CreateDummyWalletDatabase());
|
||||
std::vector<std::unique_ptr<CWalletTx>> wtxn;
|
||||
|
||||
// Copied from src/wallet/test/coinselector_tests.cpp
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ static void WalletBalance(benchmark::Bench& bench, const bool set_dirty, const b
|
|||
|
||||
NodeContext node;
|
||||
std::unique_ptr<interfaces::Chain> chain = interfaces::MakeChain(node);
|
||||
CWallet wallet{chain.get(), WalletLocation(), CreateMockWalletDatabase()};
|
||||
CWallet wallet{chain.get(), "", CreateMockWalletDatabase()};
|
||||
{
|
||||
wallet.SetupLegacyScriptPubKeyMan();
|
||||
bool first_run;
|
||||
|
|
|
|||
|
|
@ -529,15 +529,22 @@ public:
|
|||
void setMockTime(int64_t time) override { return SetMockTime(time); }
|
||||
|
||||
//! WalletClient methods
|
||||
std::unique_ptr<Wallet> createWallet(const std::string& name, const SecureString& passphrase, uint64_t wallet_creation_flags, WalletCreationStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings) override
|
||||
std::unique_ptr<Wallet> createWallet(const std::string& name, const SecureString& passphrase, uint64_t wallet_creation_flags, bilingual_str& error, std::vector<bilingual_str>& warnings) override
|
||||
{
|
||||
std::shared_ptr<CWallet> wallet;
|
||||
status = CreateWallet(*m_context.chain, passphrase, wallet_creation_flags, name, true /* load_on_start */, error, warnings, wallet);
|
||||
return MakeWallet(std::move(wallet));
|
||||
DatabaseOptions options;
|
||||
DatabaseStatus status;
|
||||
options.require_create = true;
|
||||
options.create_flags = wallet_creation_flags;
|
||||
options.create_passphrase = passphrase;
|
||||
return MakeWallet(CreateWallet(*m_context.chain, name, true /* load_on_start */, options, status, error, warnings));
|
||||
}
|
||||
std::unique_ptr<Wallet> loadWallet(const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings) override
|
||||
{
|
||||
return MakeWallet(LoadWallet(*m_context.chain, WalletLocation(name), true /* load_on_start */, error, warnings));
|
||||
DatabaseOptions options;
|
||||
DatabaseStatus status;
|
||||
options.require_existing = true;
|
||||
return MakeWallet(LoadWallet(*m_context.chain, name, true /* load_on_start */, options, status, error, warnings));
|
||||
}
|
||||
std::string getWalletDir() override
|
||||
{
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ class CWallet;
|
|||
enum class FeeReason;
|
||||
enum class OutputType;
|
||||
enum class TransactionError;
|
||||
enum class WalletCreationStatus;
|
||||
enum isminetype : unsigned int;
|
||||
struct CRecipient;
|
||||
struct PartiallySignedTransaction;
|
||||
|
|
@ -313,7 +312,7 @@ class WalletClient : public ChainClient
|
|||
{
|
||||
public:
|
||||
//! Create new wallet.
|
||||
virtual std::unique_ptr<Wallet> createWallet(const std::string& name, const SecureString& passphrase, uint64_t wallet_creation_flags, WalletCreationStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings) = 0;
|
||||
virtual std::unique_ptr<Wallet> createWallet(const std::string& name, const SecureString& passphrase, uint64_t wallet_creation_flags, bilingual_str& error, std::vector<bilingual_str>& warnings) = 0;
|
||||
|
||||
//! Load existing wallet.
|
||||
virtual std::unique_ptr<Wallet> loadWallet(const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings) = 0;
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ void TestAddAddressesToSendBook(interfaces::Node& node)
|
|||
{
|
||||
TestChain100Setup test;
|
||||
node.setContext(&test.m_node);
|
||||
std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), WalletLocation(), CreateMockWalletDatabase());
|
||||
std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), "", CreateMockWalletDatabase());
|
||||
wallet->SetupLegacyScriptPubKeyMan();
|
||||
bool firstRun;
|
||||
wallet->LoadWallet(firstRun);
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ void TestGUI(interfaces::Node& node)
|
|||
test.CreateAndProcessBlock({}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey()));
|
||||
}
|
||||
node.setContext(&test.m_node);
|
||||
std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), WalletLocation(), CreateMockWalletDatabase());
|
||||
std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), "", CreateMockWalletDatabase());
|
||||
bool firstRun;
|
||||
wallet->LoadWallet(firstRun);
|
||||
{
|
||||
|
|
|
|||
|
|
@ -250,10 +250,9 @@ void CreateWalletActivity::createWallet()
|
|||
}
|
||||
|
||||
QTimer::singleShot(500, worker(), [this, name, flags] {
|
||||
WalletCreationStatus status;
|
||||
std::unique_ptr<interfaces::Wallet> wallet = node().walletClient().createWallet(name, m_passphrase, flags, status, m_error_message, m_warning_message);
|
||||
std::unique_ptr<interfaces::Wallet> wallet = node().walletClient().createWallet(name, m_passphrase, flags, m_error_message, m_warning_message);
|
||||
|
||||
if (status == WalletCreationStatus::SUCCESS) m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(wallet));
|
||||
if (wallet) m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(wallet));
|
||||
|
||||
QTimer::singleShot(500, this, &CreateWalletActivity::finish);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -52,18 +52,6 @@ bool WalletDatabaseFileId::operator==(const WalletDatabaseFileId& rhs) const
|
|||
return memcmp(value, &rhs.value, sizeof(value)) == 0;
|
||||
}
|
||||
|
||||
bool IsBDBWalletLoaded(const fs::path& wallet_path)
|
||||
{
|
||||
fs::path env_directory;
|
||||
std::string database_filename;
|
||||
SplitWalletPath(wallet_path, env_directory, database_filename);
|
||||
LOCK(cs_db);
|
||||
auto env = g_dbenvs.find(env_directory.string());
|
||||
if (env == g_dbenvs.end()) return false;
|
||||
auto database = env->second.lock();
|
||||
return database && database->IsDatabaseLoaded(database_filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param[in] wallet_path Path to wallet directory. Or (for backwards compatibility only) a path to a berkeley btree data file inside a wallet directory.
|
||||
* @param[out] database_filename Filename of berkeley btree data file inside the wallet directory.
|
||||
|
|
@ -371,7 +359,6 @@ void BerkeleyDatabase::Open(const char* pszMode)
|
|||
if (ret != 0) {
|
||||
throw std::runtime_error(strprintf("BerkeleyDatabase: Error %d, can't open database %s", ret, strFile));
|
||||
}
|
||||
m_file_path = (env->Directory() / strFile).string();
|
||||
|
||||
// Call CheckUniqueFileid on the containing BDB environment to
|
||||
// avoid BDB data consistency bugs that happen when different data
|
||||
|
|
@ -824,3 +811,35 @@ std::unique_ptr<DatabaseBatch> BerkeleyDatabase::MakeBatch(const char* mode, boo
|
|||
{
|
||||
return MakeUnique<BerkeleyBatch>(*this, mode, flush_on_close);
|
||||
}
|
||||
|
||||
bool ExistsBerkeleyDatabase(const fs::path& path)
|
||||
{
|
||||
fs::path env_directory;
|
||||
std::string data_filename;
|
||||
SplitWalletPath(path, env_directory, data_filename);
|
||||
return IsBerkeleyBtree(env_directory / data_filename);
|
||||
}
|
||||
|
||||
std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error)
|
||||
{
|
||||
std::unique_ptr<BerkeleyDatabase> db;
|
||||
{
|
||||
LOCK(cs_db); // Lock env.m_databases until insert in BerkeleyDatabase constructor
|
||||
std::string data_filename;
|
||||
std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(path, data_filename);
|
||||
if (env->m_databases.count(data_filename)) {
|
||||
error = Untranslated(strprintf("Refusing to load database. Data file '%s' is already loaded.", (env->Directory() / data_filename).string()));
|
||||
status = DatabaseStatus::FAILED_ALREADY_LOADED;
|
||||
return nullptr;
|
||||
}
|
||||
db = MakeUnique<BerkeleyDatabase>(std::move(env), std::move(data_filename));
|
||||
}
|
||||
|
||||
if (options.verify && !db->Verify(error)) {
|
||||
status = DatabaseStatus::FAILED_VERIFY;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
status = DatabaseStatus::SUCCESS;
|
||||
return db;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ public:
|
|||
|
||||
bool IsMock() const { return fMockDb; }
|
||||
bool IsInitialized() const { return fDbEnvInit; }
|
||||
bool IsDatabaseLoaded(const std::string& db_filename) const { return m_databases.find(db_filename) != m_databases.end(); }
|
||||
fs::path Directory() const { return strPath; }
|
||||
|
||||
bool Open(bilingual_str& error);
|
||||
|
|
@ -87,8 +86,8 @@ public:
|
|||
/** Get BerkeleyEnvironment and database filename given a wallet path. */
|
||||
std::shared_ptr<BerkeleyEnvironment> GetWalletEnv(const fs::path& wallet_path, std::string& database_filename);
|
||||
|
||||
/** Return whether a BDB wallet database is currently loaded. */
|
||||
bool IsBDBWalletLoaded(const fs::path& wallet_path);
|
||||
/** Check format of database file */
|
||||
bool IsBerkeleyBtree(const fs::path& path);
|
||||
|
||||
class BerkeleyBatch;
|
||||
|
||||
|
|
@ -143,7 +142,10 @@ public:
|
|||
void ReloadDbEnv() override;
|
||||
|
||||
/** Verifies the environment and database file */
|
||||
bool Verify(bilingual_str& error) override;
|
||||
bool Verify(bilingual_str& error);
|
||||
|
||||
/** Return path to main database filename */
|
||||
std::string Filename() override { return (env->Directory() / strFile).string(); }
|
||||
|
||||
/**
|
||||
* Pointer to shared database environment.
|
||||
|
|
@ -224,4 +226,10 @@ public:
|
|||
|
||||
std::string BerkeleyDatabaseVersion();
|
||||
|
||||
//! Check if Berkeley database exists at specified path.
|
||||
bool ExistsBerkeleyDatabase(const fs::path& path);
|
||||
|
||||
//! Return object giving access to Berkeley database at specified path.
|
||||
std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
|
||||
|
||||
#endif // BITCOIN_WALLET_BDB_H
|
||||
|
|
|
|||
|
|
@ -23,11 +23,3 @@ void SplitWalletPath(const fs::path& wallet_path, fs::path& env_directory, std::
|
|||
database_filename = "wallet.dat";
|
||||
}
|
||||
}
|
||||
|
||||
fs::path WalletDataFilePath(const fs::path& wallet_path)
|
||||
{
|
||||
fs::path env_directory;
|
||||
std::string database_filename;
|
||||
SplitWalletPath(wallet_path, env_directory, database_filename);
|
||||
return env_directory / database_filename;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <clientversion.h>
|
||||
#include <fs.h>
|
||||
#include <streams.h>
|
||||
#include <support/allocators/secure.h>
|
||||
#include <util/memory.h>
|
||||
|
||||
#include <atomic>
|
||||
|
|
@ -17,8 +18,6 @@
|
|||
|
||||
struct bilingual_str;
|
||||
|
||||
/** Given a wallet directory path or legacy file path, return path to main data file in the wallet database. */
|
||||
fs::path WalletDataFilePath(const fs::path& wallet_path);
|
||||
void SplitWalletPath(const fs::path& wallet_path, fs::path& env_directory, std::string& database_filename);
|
||||
|
||||
/** RAII class that provides access to a WalletDatabase */
|
||||
|
|
@ -141,16 +140,14 @@ public:
|
|||
|
||||
virtual void ReloadDbEnv() = 0;
|
||||
|
||||
/** Return path to main database file for logs and error messages. */
|
||||
virtual std::string Filename() = 0;
|
||||
|
||||
std::atomic<unsigned int> nUpdateCounter;
|
||||
unsigned int nLastSeen;
|
||||
unsigned int nLastFlushed;
|
||||
int64_t nLastWalletUpdate;
|
||||
|
||||
/** Verifies the environment and database file */
|
||||
virtual bool Verify(bilingual_str& error) = 0;
|
||||
|
||||
std::string m_file_path;
|
||||
|
||||
/** Make a DatabaseBatch connected to this database */
|
||||
virtual std::unique_ptr<DatabaseBatch> MakeBatch(const char* mode = "r+", bool flush_on_close = true) = 0;
|
||||
};
|
||||
|
|
@ -191,8 +188,34 @@ public:
|
|||
bool PeriodicFlush() override { return true; }
|
||||
void IncrementUpdateCounter() override { ++nUpdateCounter; }
|
||||
void ReloadDbEnv() override {}
|
||||
bool Verify(bilingual_str& errorStr) override { return true; }
|
||||
std::string Filename() override { return "dummy"; }
|
||||
std::unique_ptr<DatabaseBatch> MakeBatch(const char* mode = "r+", bool flush_on_close = true) override { return MakeUnique<DummyBatch>(); }
|
||||
};
|
||||
|
||||
enum class DatabaseFormat {
|
||||
BERKELEY,
|
||||
};
|
||||
|
||||
struct DatabaseOptions {
|
||||
bool require_existing = false;
|
||||
bool require_create = false;
|
||||
uint64_t create_flags = 0;
|
||||
SecureString create_passphrase;
|
||||
bool verify = true;
|
||||
};
|
||||
|
||||
enum class DatabaseStatus {
|
||||
SUCCESS,
|
||||
FAILED_BAD_PATH,
|
||||
FAILED_BAD_FORMAT,
|
||||
FAILED_ALREADY_LOADED,
|
||||
FAILED_ALREADY_EXISTS,
|
||||
FAILED_NOT_FOUND,
|
||||
FAILED_CREATE,
|
||||
FAILED_VERIFY,
|
||||
FAILED_ENCRYPT,
|
||||
};
|
||||
|
||||
std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
|
||||
|
||||
#endif // BITCOIN_WALLET_DB_H
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <wallet/load.h>
|
||||
|
||||
#include <fs.h>
|
||||
#include <interfaces/chain.h>
|
||||
#include <scheduler.h>
|
||||
#include <util/string.h>
|
||||
|
|
@ -44,18 +45,18 @@ bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wal
|
|||
std::set<fs::path> wallet_paths;
|
||||
|
||||
for (const auto& wallet_file : wallet_files) {
|
||||
WalletLocation location(wallet_file);
|
||||
const fs::path path = fs::absolute(wallet_file, GetWalletDir());
|
||||
|
||||
if (!wallet_paths.insert(location.GetPath()).second) {
|
||||
if (!wallet_paths.insert(path).second) {
|
||||
chain.initError(strprintf(_("Error loading wallet %s. Duplicate -wallet filename specified."), wallet_file));
|
||||
return false;
|
||||
}
|
||||
|
||||
DatabaseOptions options;
|
||||
DatabaseStatus status;
|
||||
options.verify = true;
|
||||
bilingual_str error_string;
|
||||
std::vector<bilingual_str> warnings;
|
||||
bool verify_success = CWallet::Verify(chain, location, error_string, warnings);
|
||||
if (!warnings.empty()) chain.initWarning(Join(warnings, Untranslated("\n")));
|
||||
if (!verify_success) {
|
||||
if (!MakeWalletDatabase(wallet_file, options, status, error_string)) {
|
||||
chain.initError(error_string);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -67,10 +68,14 @@ bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wal
|
|||
bool LoadWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files)
|
||||
{
|
||||
try {
|
||||
for (const std::string& walletFile : wallet_files) {
|
||||
for (const std::string& name : wallet_files) {
|
||||
DatabaseOptions options;
|
||||
DatabaseStatus status;
|
||||
options.verify = false; // No need to verify, assuming verified earlier in VerifyWallets()
|
||||
bilingual_str error;
|
||||
std::vector<bilingual_str> warnings;
|
||||
std::shared_ptr<CWallet> pwallet = CWallet::CreateWalletFromFile(chain, WalletLocation(walletFile), error, warnings);
|
||||
std::unique_ptr<WalletDatabase> database = MakeWalletDatabase(name, options, status, error);
|
||||
std::shared_ptr<CWallet> pwallet = database ? CWallet::Create(chain, name, std::move(database), options.create_flags, error, warnings) : nullptr;
|
||||
if (!warnings.empty()) chain.initWarning(Join(warnings, Untranslated("\n")));
|
||||
if (!pwallet) {
|
||||
chain.initError(error);
|
||||
|
|
|
|||
|
|
@ -2665,23 +2665,21 @@ static UniValue loadwallet(const JSONRPCRequest& request)
|
|||
}.Check(request);
|
||||
|
||||
WalletContext& context = EnsureWalletContext(request.context);
|
||||
WalletLocation location(request.params[0].get_str());
|
||||
|
||||
if (!location.Exists()) {
|
||||
throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Wallet " + location.GetName() + " not found.");
|
||||
} else if (fs::is_directory(location.GetPath())) {
|
||||
// The given filename is a directory. Check that there's a wallet.dat file.
|
||||
fs::path wallet_dat_file = location.GetPath() / "wallet.dat";
|
||||
if (fs::symlink_status(wallet_dat_file).type() == fs::file_not_found) {
|
||||
throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Directory " + location.GetName() + " does not contain a wallet.dat file.");
|
||||
}
|
||||
}
|
||||
const std::string name(request.params[0].get_str());
|
||||
|
||||
DatabaseOptions options;
|
||||
DatabaseStatus status;
|
||||
options.require_existing = true;
|
||||
bilingual_str error;
|
||||
std::vector<bilingual_str> warnings;
|
||||
Optional<bool> load_on_start = request.params[1].isNull() ? nullopt : Optional<bool>(request.params[1].get_bool());
|
||||
std::shared_ptr<CWallet> const wallet = LoadWallet(*context.chain, location, load_on_start, error, warnings);
|
||||
if (!wallet) throw JSONRPCError(RPC_WALLET_ERROR, error.original);
|
||||
std::shared_ptr<CWallet> const wallet = LoadWallet(*context.chain, name, load_on_start, options, status, error, warnings);
|
||||
if (!wallet) {
|
||||
// Map bad format to not found, since bad format is returned when the
|
||||
// wallet directory exists, but doesn't contain a data file.
|
||||
RPCErrorCode code = status == DatabaseStatus::FAILED_NOT_FOUND || status == DatabaseStatus::FAILED_BAD_FORMAT ? RPC_WALLET_NOT_FOUND : RPC_WALLET_ERROR;
|
||||
throw JSONRPCError(code, error.original);
|
||||
}
|
||||
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
obj.pushKV("name", wallet->GetName());
|
||||
|
|
@ -2810,18 +2808,17 @@ static UniValue createwallet(const JSONRPCRequest& request)
|
|||
warnings.emplace_back(Untranslated("Wallet is an experimental descriptor wallet"));
|
||||
}
|
||||
|
||||
DatabaseOptions options;
|
||||
DatabaseStatus status;
|
||||
options.require_create = true;
|
||||
options.create_flags = flags;
|
||||
options.create_passphrase = passphrase;
|
||||
bilingual_str error;
|
||||
std::shared_ptr<CWallet> wallet;
|
||||
Optional<bool> load_on_start = request.params[6].isNull() ? nullopt : Optional<bool>(request.params[6].get_bool());
|
||||
WalletCreationStatus status = CreateWallet(*context.chain, passphrase, flags, request.params[0].get_str(), load_on_start, error, warnings, wallet);
|
||||
switch (status) {
|
||||
case WalletCreationStatus::CREATION_FAILED:
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, error.original);
|
||||
case WalletCreationStatus::ENCRYPTION_FAILED:
|
||||
throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, error.original);
|
||||
case WalletCreationStatus::SUCCESS:
|
||||
break;
|
||||
// no default case, so the compiler can warn about missing cases
|
||||
std::shared_ptr<CWallet> wallet = CreateWallet(*context.chain, request.params[0].get_str(), load_on_start, options, status, error, warnings);
|
||||
if (!wallet) {
|
||||
RPCErrorCode code = status == DatabaseStatus::FAILED_ENCRYPT ? RPC_WALLET_ENCRYPTION_FAILED : RPC_WALLET_ERROR;
|
||||
throw JSONRPCError(code, error.original);
|
||||
}
|
||||
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
|
|
|
|||
|
|
@ -23,6 +23,13 @@ static bool KeyFilter(const std::string& type)
|
|||
|
||||
bool RecoverDatabaseFile(const fs::path& file_path, bilingual_str& error, std::vector<bilingual_str>& warnings)
|
||||
{
|
||||
DatabaseOptions options;
|
||||
DatabaseStatus status;
|
||||
options.require_existing = true;
|
||||
options.verify = false;
|
||||
std::unique_ptr<WalletDatabase> database = MakeDatabase(file_path, options, status, error);
|
||||
if (!database) return false;
|
||||
|
||||
std::string filename;
|
||||
std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(file_path, filename);
|
||||
|
||||
|
|
@ -123,7 +130,7 @@ bool RecoverDatabaseFile(const fs::path& file_path, bilingual_str& error, std::v
|
|||
}
|
||||
|
||||
DbTxn* ptxn = env->TxnBegin();
|
||||
CWallet dummyWallet(nullptr, WalletLocation(), CreateDummyWalletDatabase());
|
||||
CWallet dummyWallet(nullptr, "", CreateDummyWalletDatabase());
|
||||
for (KeyValPair& row : salvagedData)
|
||||
{
|
||||
/* Filter for only private key type KV pairs to be added to the salvaged wallet */
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ typedef std::set<CInputCoin> CoinSet;
|
|||
static std::vector<COutput> vCoins;
|
||||
static NodeContext testNode;
|
||||
static auto testChain = interfaces::MakeChain(testNode);
|
||||
static CWallet testWallet(testChain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
static CWallet testWallet(testChain.get(), "", CreateDummyWalletDatabase());
|
||||
static CAmount balance = 0;
|
||||
|
||||
CoinEligibilityFilter filter_standard(1, 6, 0);
|
||||
|
|
@ -298,7 +298,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
|
|||
// Make sure that can use BnB when there are preset inputs
|
||||
empty_wallet();
|
||||
{
|
||||
std::unique_ptr<CWallet> wallet = MakeUnique<CWallet>(m_chain.get(), WalletLocation(), CreateMockWalletDatabase());
|
||||
std::unique_ptr<CWallet> wallet = MakeUnique<CWallet>(m_chain.get(), "", CreateMockWalletDatabase());
|
||||
bool firstRun;
|
||||
wallet->LoadWallet(firstRun);
|
||||
wallet->SetupLegacyScriptPubKeyMan();
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
|
||||
// P2PK compressed
|
||||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
|
||||
keystore.SetupLegacyScriptPubKeyMan();
|
||||
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
|
||||
scriptPubKey = GetScriptForRawPubKey(pubkeys[0]);
|
||||
|
|
@ -52,7 +52,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
|
||||
// P2PK uncompressed
|
||||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
|
||||
keystore.SetupLegacyScriptPubKeyMan();
|
||||
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
|
||||
scriptPubKey = GetScriptForRawPubKey(uncompressedPubkey);
|
||||
|
|
@ -69,7 +69,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
|
||||
// P2PKH compressed
|
||||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
|
||||
keystore.SetupLegacyScriptPubKeyMan();
|
||||
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
|
||||
scriptPubKey = GetScriptForDestination(PKHash(pubkeys[0]));
|
||||
|
|
@ -86,7 +86,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
|
||||
// P2PKH uncompressed
|
||||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
|
||||
keystore.SetupLegacyScriptPubKeyMan();
|
||||
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
|
||||
scriptPubKey = GetScriptForDestination(PKHash(uncompressedPubkey));
|
||||
|
|
@ -103,7 +103,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
|
||||
// P2SH
|
||||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
|
||||
keystore.SetupLegacyScriptPubKeyMan();
|
||||
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
|
||||
|
||||
|
|
@ -127,7 +127,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
|
||||
// (P2PKH inside) P2SH inside P2SH (invalid)
|
||||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
|
||||
keystore.SetupLegacyScriptPubKeyMan();
|
||||
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
|
||||
|
||||
|
|
@ -145,7 +145,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
|
||||
// (P2PKH inside) P2SH inside P2WSH (invalid)
|
||||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
|
||||
keystore.SetupLegacyScriptPubKeyMan();
|
||||
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
|
||||
|
||||
|
|
@ -163,7 +163,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
|
||||
// P2WPKH inside P2WSH (invalid)
|
||||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
|
||||
keystore.SetupLegacyScriptPubKeyMan();
|
||||
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
|
||||
|
||||
|
|
@ -179,7 +179,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
|
||||
// (P2PKH inside) P2WSH inside P2WSH (invalid)
|
||||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
|
||||
keystore.SetupLegacyScriptPubKeyMan();
|
||||
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
|
||||
|
||||
|
|
@ -197,7 +197,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
|
||||
// P2WPKH compressed
|
||||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
|
||||
keystore.SetupLegacyScriptPubKeyMan();
|
||||
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
|
||||
|
|
@ -212,7 +212,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
|
||||
// P2WPKH uncompressed
|
||||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
|
||||
keystore.SetupLegacyScriptPubKeyMan();
|
||||
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
|
||||
|
|
@ -231,7 +231,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
|
||||
// scriptPubKey multisig
|
||||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
|
||||
keystore.SetupLegacyScriptPubKeyMan();
|
||||
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
|
||||
|
||||
|
|
@ -262,7 +262,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
|
||||
// P2SH multisig
|
||||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
|
||||
keystore.SetupLegacyScriptPubKeyMan();
|
||||
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
|
||||
|
|
@ -283,7 +283,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
|
||||
// P2WSH multisig with compressed keys
|
||||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
|
||||
keystore.SetupLegacyScriptPubKeyMan();
|
||||
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
|
||||
|
|
@ -309,7 +309,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
|
||||
// P2WSH multisig with uncompressed key
|
||||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
|
||||
keystore.SetupLegacyScriptPubKeyMan();
|
||||
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
|
||||
|
|
@ -335,7 +335,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
|
||||
// P2WSH multisig wrapped in P2SH
|
||||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
|
||||
keystore.SetupLegacyScriptPubKeyMan();
|
||||
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
|
||||
|
||||
|
|
@ -362,7 +362,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
|
||||
// OP_RETURN
|
||||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
|
||||
keystore.SetupLegacyScriptPubKeyMan();
|
||||
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
|
||||
|
|
@ -376,7 +376,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
|
||||
// witness unspendable
|
||||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
|
||||
keystore.SetupLegacyScriptPubKeyMan();
|
||||
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
|
||||
|
|
@ -390,7 +390,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
|
||||
// witness unknown
|
||||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
|
||||
keystore.SetupLegacyScriptPubKeyMan();
|
||||
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
|
||||
|
|
@ -404,7 +404,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
|
|||
|
||||
// Nonstandard
|
||||
{
|
||||
CWallet keystore(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
|
||||
keystore.SetupLegacyScriptPubKeyMan();
|
||||
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
|
||||
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ BOOST_AUTO_TEST_CASE(CanProvide)
|
|||
// Set up wallet and keyman variables.
|
||||
NodeContext node;
|
||||
std::unique_ptr<interfaces::Chain> chain = interfaces::MakeChain(node);
|
||||
CWallet wallet(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
CWallet wallet(chain.get(), "", CreateDummyWalletDatabase());
|
||||
LegacyScriptPubKeyMan& keyman = *wallet.GetOrCreateLegacyScriptPubKeyMan();
|
||||
|
||||
// Make a 1 of 2 multisig script
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
WalletTestingSetup::WalletTestingSetup(const std::string& chainName)
|
||||
: TestingSetup(chainName),
|
||||
m_wallet(m_chain.get(), WalletLocation(), CreateMockWalletDatabase())
|
||||
m_wallet(m_chain.get(), "", CreateMockWalletDatabase())
|
||||
{
|
||||
bool fFirstRun;
|
||||
m_wallet.LoadWallet(fFirstRun);
|
||||
|
|
|
|||
|
|
@ -37,9 +37,12 @@ BOOST_FIXTURE_TEST_SUITE(wallet_tests, WalletTestingSetup)
|
|||
|
||||
static std::shared_ptr<CWallet> TestLoadWallet(interfaces::Chain& chain)
|
||||
{
|
||||
DatabaseOptions options;
|
||||
DatabaseStatus status;
|
||||
bilingual_str error;
|
||||
std::vector<bilingual_str> warnings;
|
||||
auto wallet = CWallet::CreateWalletFromFile(chain, WalletLocation(""), error, warnings);
|
||||
auto database = MakeWalletDatabase("", options, status, error);
|
||||
auto wallet = CWallet::Create(chain, "", std::move(database), options.create_flags, error, warnings);
|
||||
wallet->postInitProcess();
|
||||
return wallet;
|
||||
}
|
||||
|
|
@ -89,7 +92,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
|
|||
|
||||
// Verify ScanForWalletTransactions fails to read an unknown start block.
|
||||
{
|
||||
CWallet wallet(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
CWallet wallet(chain.get(), "", CreateDummyWalletDatabase());
|
||||
{
|
||||
LOCK(wallet.cs_wallet);
|
||||
wallet.SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());
|
||||
|
|
@ -108,7 +111,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
|
|||
// Verify ScanForWalletTransactions picks up transactions in both the old
|
||||
// and new block files.
|
||||
{
|
||||
CWallet wallet(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
CWallet wallet(chain.get(), "", CreateDummyWalletDatabase());
|
||||
{
|
||||
LOCK(wallet.cs_wallet);
|
||||
wallet.SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());
|
||||
|
|
@ -134,7 +137,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
|
|||
// Verify ScanForWalletTransactions only picks transactions in the new block
|
||||
// file.
|
||||
{
|
||||
CWallet wallet(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
CWallet wallet(chain.get(), "", CreateDummyWalletDatabase());
|
||||
{
|
||||
LOCK(wallet.cs_wallet);
|
||||
wallet.SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());
|
||||
|
|
@ -159,7 +162,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
|
|||
|
||||
// Verify ScanForWalletTransactions scans no blocks.
|
||||
{
|
||||
CWallet wallet(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
CWallet wallet(chain.get(), "", CreateDummyWalletDatabase());
|
||||
{
|
||||
LOCK(wallet.cs_wallet);
|
||||
wallet.SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());
|
||||
|
|
@ -198,7 +201,7 @@ BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup)
|
|||
// before the missing block, and success for a key whose creation time is
|
||||
// after.
|
||||
{
|
||||
std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), "", CreateDummyWalletDatabase());
|
||||
wallet->SetupLegacyScriptPubKeyMan();
|
||||
WITH_LOCK(wallet->cs_wallet, wallet->SetLastBlockProcessed(newTip->nHeight, newTip->GetBlockHash()));
|
||||
AddWallet(wallet);
|
||||
|
|
@ -263,7 +266,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
|
|||
|
||||
// Import key into wallet and call dumpwallet to create backup file.
|
||||
{
|
||||
std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), "", CreateDummyWalletDatabase());
|
||||
{
|
||||
auto spk_man = wallet->GetOrCreateLegacyScriptPubKeyMan();
|
||||
LOCK2(wallet->cs_wallet, spk_man->cs_KeyStore);
|
||||
|
|
@ -285,7 +288,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
|
|||
// Call importwallet RPC and verify all blocks with timestamps >= BLOCK_TIME
|
||||
// were scanned, and no prior blocks were scanned.
|
||||
{
|
||||
std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), "", CreateDummyWalletDatabase());
|
||||
LOCK(wallet->cs_wallet);
|
||||
wallet->SetupLegacyScriptPubKeyMan();
|
||||
|
||||
|
|
@ -321,7 +324,7 @@ BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
|
|||
NodeContext node;
|
||||
auto chain = interfaces::MakeChain(node);
|
||||
|
||||
CWallet wallet(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
CWallet wallet(chain.get(), "", CreateDummyWalletDatabase());
|
||||
auto spk_man = wallet.GetOrCreateLegacyScriptPubKeyMan();
|
||||
CWalletTx wtx(&wallet, m_coinbase_txns.back());
|
||||
|
||||
|
|
@ -496,7 +499,7 @@ public:
|
|||
ListCoinsTestingSetup()
|
||||
{
|
||||
CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
|
||||
wallet = MakeUnique<CWallet>(m_chain.get(), WalletLocation(), CreateMockWalletDatabase());
|
||||
wallet = MakeUnique<CWallet>(m_chain.get(), "", CreateMockWalletDatabase());
|
||||
{
|
||||
LOCK2(wallet->cs_wallet, ::cs_main);
|
||||
wallet->SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash());
|
||||
|
|
@ -614,7 +617,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup)
|
|||
{
|
||||
NodeContext node;
|
||||
auto chain = interfaces::MakeChain(node);
|
||||
std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), CreateDummyWalletDatabase());
|
||||
std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), "", CreateDummyWalletDatabase());
|
||||
wallet->SetupLegacyScriptPubKeyMan();
|
||||
wallet->SetMinVersion(FEATURE_LATEST);
|
||||
wallet->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
|
||||
|
|
|
|||
|
|
@ -208,15 +208,16 @@ void UnloadWallet(std::shared_ptr<CWallet>&& wallet)
|
|||
}
|
||||
|
||||
namespace {
|
||||
std::shared_ptr<CWallet> LoadWalletInternal(interfaces::Chain& chain, const WalletLocation& location, Optional<bool> load_on_start, bilingual_str& error, std::vector<bilingual_str>& warnings)
|
||||
std::shared_ptr<CWallet> LoadWalletInternal(interfaces::Chain& chain, const std::string& name, Optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings)
|
||||
{
|
||||
try {
|
||||
if (!CWallet::Verify(chain, location, error, warnings)) {
|
||||
std::unique_ptr<WalletDatabase> database = MakeWalletDatabase(name, options, status, error);
|
||||
if (!database) {
|
||||
error = Untranslated("Wallet file verification failed.") + Untranslated(" ") + error;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<CWallet> wallet = CWallet::CreateWalletFromFile(chain, location, error, warnings);
|
||||
std::shared_ptr<CWallet> wallet = CWallet::Create(chain, name, std::move(database), options.create_flags, error, warnings);
|
||||
if (!wallet) {
|
||||
error = Untranslated("Wallet loading failed.") + Untranslated(" ") + error;
|
||||
return nullptr;
|
||||
|
|
@ -225,7 +226,7 @@ std::shared_ptr<CWallet> LoadWalletInternal(interfaces::Chain& chain, const Wall
|
|||
wallet->postInitProcess();
|
||||
|
||||
// Write the wallet setting
|
||||
UpdateWalletSetting(chain, location.GetName(), load_on_start, warnings);
|
||||
UpdateWalletSetting(chain, name, load_on_start, warnings);
|
||||
|
||||
return wallet;
|
||||
} catch (const std::runtime_error& e) {
|
||||
|
|
@ -235,20 +236,23 @@ std::shared_ptr<CWallet> LoadWalletInternal(interfaces::Chain& chain, const Wall
|
|||
}
|
||||
} // namespace
|
||||
|
||||
std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const WalletLocation& location, Optional<bool> load_on_start, bilingual_str& error, std::vector<bilingual_str>& warnings)
|
||||
std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, Optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings)
|
||||
{
|
||||
auto result = WITH_LOCK(g_loading_wallet_mutex, return g_loading_wallet_set.insert(location.GetName()));
|
||||
auto result = WITH_LOCK(g_loading_wallet_mutex, return g_loading_wallet_set.insert(name));
|
||||
if (!result.second) {
|
||||
error = Untranslated("Wallet already being loading.");
|
||||
return nullptr;
|
||||
}
|
||||
auto wallet = LoadWalletInternal(chain, location, load_on_start, error, warnings);
|
||||
auto wallet = LoadWalletInternal(chain, name, load_on_start, options, status, error, warnings);
|
||||
WITH_LOCK(g_loading_wallet_mutex, g_loading_wallet_set.erase(result.first));
|
||||
return wallet;
|
||||
}
|
||||
|
||||
WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, Optional<bool> load_on_start, bilingual_str& error, std::vector<bilingual_str>& warnings, std::shared_ptr<CWallet>& result)
|
||||
std::shared_ptr<CWallet> CreateWallet(interfaces::Chain& chain, const std::string& name, Optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings)
|
||||
{
|
||||
uint64_t wallet_creation_flags = options.create_flags;
|
||||
const SecureString& passphrase = options.create_passphrase;
|
||||
|
||||
// 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);
|
||||
|
||||
|
|
@ -257,43 +261,42 @@ WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString&
|
|||
wallet_creation_flags |= WALLET_FLAG_BLANK_WALLET;
|
||||
}
|
||||
|
||||
// Check the wallet file location
|
||||
WalletLocation location(name);
|
||||
if (location.Exists()) {
|
||||
error = strprintf(Untranslated("Wallet %s already exists."), location.GetName());
|
||||
return WalletCreationStatus::CREATION_FAILED;
|
||||
}
|
||||
|
||||
// Wallet::Verify will check if we're trying to create a wallet with a duplicate name.
|
||||
if (!CWallet::Verify(chain, location, error, warnings)) {
|
||||
std::unique_ptr<WalletDatabase> database = MakeWalletDatabase(name, options, status, error);
|
||||
if (!database) {
|
||||
error = Untranslated("Wallet file verification failed.") + Untranslated(" ") + error;
|
||||
return WalletCreationStatus::CREATION_FAILED;
|
||||
status = DatabaseStatus::FAILED_VERIFY;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Do not allow a passphrase when private keys are disabled
|
||||
if (!passphrase.empty() && (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
|
||||
error = Untranslated("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;
|
||||
status = DatabaseStatus::FAILED_CREATE;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Make the wallet
|
||||
std::shared_ptr<CWallet> wallet = CWallet::CreateWalletFromFile(chain, location, error, warnings, wallet_creation_flags);
|
||||
std::shared_ptr<CWallet> wallet = CWallet::Create(chain, name, std::move(database), wallet_creation_flags, error, warnings);
|
||||
if (!wallet) {
|
||||
error = Untranslated("Wallet creation failed.") + Untranslated(" ") + error;
|
||||
return WalletCreationStatus::CREATION_FAILED;
|
||||
status = DatabaseStatus::FAILED_CREATE;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Encrypt the wallet
|
||||
if (!passphrase.empty() && !(wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
|
||||
if (!wallet->EncryptWallet(passphrase)) {
|
||||
error = Untranslated("Error: Wallet created but failed to encrypt.");
|
||||
return WalletCreationStatus::ENCRYPTION_FAILED;
|
||||
status = DatabaseStatus::FAILED_ENCRYPT;
|
||||
return nullptr;
|
||||
}
|
||||
if (!create_blank) {
|
||||
// Unlock the wallet
|
||||
if (!wallet->Unlock(passphrase)) {
|
||||
error = Untranslated("Error: Wallet was encrypted but could not be unlocked");
|
||||
return WalletCreationStatus::ENCRYPTION_FAILED;
|
||||
status = DatabaseStatus::FAILED_ENCRYPT;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Set a seed for the wallet
|
||||
|
|
@ -305,7 +308,8 @@ WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString&
|
|||
for (auto spk_man : wallet->GetActiveScriptPubKeyMans()) {
|
||||
if (!spk_man->SetupGeneration()) {
|
||||
error = Untranslated("Unable to generate initial keys");
|
||||
return WalletCreationStatus::CREATION_FAILED;
|
||||
status = DatabaseStatus::FAILED_CREATE;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -317,12 +321,12 @@ WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString&
|
|||
}
|
||||
AddWallet(wallet);
|
||||
wallet->postInitProcess();
|
||||
result = wallet;
|
||||
|
||||
// Write the wallet settings
|
||||
UpdateWalletSetting(chain, name, load_on_start, warnings);
|
||||
|
||||
return WalletCreationStatus::SUCCESS;
|
||||
status = DatabaseStatus::SUCCESS;
|
||||
return wallet;
|
||||
}
|
||||
|
||||
const uint256 CWalletTx::ABANDON_HASH(UINT256_ONE());
|
||||
|
|
@ -4706,7 +4710,7 @@ std::vector<std::string> CWallet::GetDestValues(const std::string& prefix) const
|
|||
return values;
|
||||
}
|
||||
|
||||
bool CWallet::Verify(interfaces::Chain& chain, const WalletLocation& location, bilingual_str& error_string, std::vector<bilingual_str>& warnings)
|
||||
std::unique_ptr<WalletDatabase> MakeWalletDatabase(const std::string& name, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error_string)
|
||||
{
|
||||
// Do some checking on wallet path. It should be either a:
|
||||
//
|
||||
|
|
@ -4714,40 +4718,25 @@ bool CWallet::Verify(interfaces::Chain& chain, const WalletLocation& location, b
|
|||
// 2. Path to an existing directory.
|
||||
// 3. Path to a symlink to a directory.
|
||||
// 4. For backwards compatibility, the name of a data file in -walletdir.
|
||||
LOCK(cs_wallets);
|
||||
const fs::path& wallet_path = location.GetPath();
|
||||
const fs::path& wallet_path = fs::absolute(name, GetWalletDir());
|
||||
fs::file_type path_type = fs::symlink_status(wallet_path).type();
|
||||
if (!(path_type == fs::file_not_found || path_type == fs::directory_file ||
|
||||
(path_type == fs::symlink_file && fs::is_directory(wallet_path)) ||
|
||||
(path_type == fs::regular_file && fs::path(location.GetName()).filename() == location.GetName()))) {
|
||||
(path_type == fs::regular_file && fs::path(name).filename() == name))) {
|
||||
error_string = Untranslated(strprintf(
|
||||
"Invalid -wallet path '%s'. -wallet path should point to a directory where wallet.dat and "
|
||||
"database/log.?????????? files can be stored, a location where such a directory could be created, "
|
||||
"or (for backwards compatibility) the name of an existing data file in -walletdir (%s)",
|
||||
location.GetName(), GetWalletDir()));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure that the wallet path doesn't clash with an existing wallet path
|
||||
if (IsWalletLoaded(wallet_path)) {
|
||||
error_string = Untranslated(strprintf("Error loading wallet %s. Duplicate -wallet filename specified.", location.GetName()));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Keep same database environment instance across Verify/Recover calls below.
|
||||
std::unique_ptr<WalletDatabase> database = CreateWalletDatabase(wallet_path);
|
||||
|
||||
try {
|
||||
return database->Verify(error_string);
|
||||
} catch (const fs::filesystem_error& e) {
|
||||
error_string = Untranslated(strprintf("Error loading wallet %s. %s", location.GetName(), fsbridge::get_filesystem_error_message(e)));
|
||||
return false;
|
||||
name, GetWalletDir()));
|
||||
status = DatabaseStatus::FAILED_BAD_PATH;
|
||||
return nullptr;
|
||||
}
|
||||
return MakeDatabase(wallet_path, options, status, error_string);
|
||||
}
|
||||
|
||||
std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, const WalletLocation& location, bilingual_str& error, std::vector<bilingual_str>& warnings, uint64_t wallet_creation_flags)
|
||||
std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::string& name, std::unique_ptr<WalletDatabase> database, uint64_t wallet_creation_flags, bilingual_str& error, std::vector<bilingual_str>& warnings)
|
||||
{
|
||||
const std::string walletFile = WalletDataFilePath(location.GetPath()).string();
|
||||
const std::string& walletFile = database->Filename();
|
||||
|
||||
chain.initMessage(_("Loading wallet...").translated);
|
||||
|
||||
|
|
@ -4755,7 +4744,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
|
|||
bool fFirstRun = true;
|
||||
// TODO: Can't use std::make_shared because we need a custom deleter but
|
||||
// should be possible to use std::allocate_shared.
|
||||
std::shared_ptr<CWallet> walletInstance(new CWallet(&chain, location, CreateWalletDatabase(location.GetPath())), ReleaseWallet);
|
||||
std::shared_ptr<CWallet> walletInstance(new CWallet(&chain, name, std::move(database)), ReleaseWallet);
|
||||
DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun);
|
||||
if (nLoadWalletRet != DBErrors::LOAD_OK) {
|
||||
if (nLoadWalletRet == DBErrors::CORRUPT) {
|
||||
|
|
|
|||
|
|
@ -55,16 +55,10 @@ bool RemoveWallet(const std::shared_ptr<CWallet>& wallet, Optional<bool> load_on
|
|||
bool RemoveWallet(const std::shared_ptr<CWallet>& wallet, Optional<bool> load_on_start);
|
||||
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, Optional<bool> load_on_start, bilingual_str& error, std::vector<bilingual_str>& warnings);
|
||||
std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, Optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings);
|
||||
std::shared_ptr<CWallet> CreateWallet(interfaces::Chain& chain, const std::string& name, Optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings);
|
||||
std::unique_ptr<interfaces::Handler> HandleLoadWallet(LoadWalletFn load_wallet);
|
||||
|
||||
enum class WalletCreationStatus {
|
||||
SUCCESS,
|
||||
CREATION_FAILED,
|
||||
ENCRYPTION_FAILED
|
||||
};
|
||||
|
||||
WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, Optional<bool> load_on_start, bilingual_str& error, std::vector<bilingual_str>& warnings, std::shared_ptr<CWallet>& result);
|
||||
std::unique_ptr<WalletDatabase> MakeWalletDatabase(const std::string& name, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
|
||||
|
||||
//! -paytxfee default
|
||||
constexpr CAmount DEFAULT_PAY_TX_FEE = 0;
|
||||
|
|
@ -792,8 +786,8 @@ private:
|
|||
/** Interface for accessing chain state. */
|
||||
interfaces::Chain* m_chain;
|
||||
|
||||
/** Wallet location which includes wallet name (see WalletLocation). */
|
||||
WalletLocation m_location;
|
||||
/** Wallet name: relative directory name or "" for default wallet. */
|
||||
std::string m_name;
|
||||
|
||||
/** Internal database handle. */
|
||||
std::unique_ptr<WalletDatabase> database;
|
||||
|
|
@ -847,20 +841,18 @@ public:
|
|||
bool SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAmountMap& mapTargetValue, std::set<CInputCoin>& setCoinsRet, CAmountMap& mapValueRet,
|
||||
const CCoinControl& coin_control, CoinSelectionParams& coin_selection_params, bool& bnb_used) const;
|
||||
|
||||
const WalletLocation& GetLocation() const { return m_location; }
|
||||
|
||||
/** Get a name for this wallet for logging/debugging purposes.
|
||||
*/
|
||||
const std::string& GetName() const { return m_location.GetName(); }
|
||||
const std::string& GetName() const { return m_name; }
|
||||
|
||||
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
|
||||
MasterKeyMap mapMasterKeys;
|
||||
unsigned int nMasterKeyMaxID = 0;
|
||||
|
||||
/** Construct wallet with specified name and database implementation. */
|
||||
CWallet(interfaces::Chain* chain, const WalletLocation& location, std::unique_ptr<WalletDatabase> database)
|
||||
CWallet(interfaces::Chain* chain, const std::string& name, std::unique_ptr<WalletDatabase> database)
|
||||
: m_chain(chain),
|
||||
m_location(location),
|
||||
m_name(name),
|
||||
database(std::move(database))
|
||||
{
|
||||
}
|
||||
|
|
@ -1277,11 +1269,8 @@ public:
|
|||
/** Mark a transaction as replaced by another transaction (e.g., BIP 125). */
|
||||
bool MarkReplaced(const uint256& originalHash, const uint256& newHash);
|
||||
|
||||
//! Verify wallet naming and perform salvage on the wallet if required
|
||||
static bool Verify(interfaces::Chain& chain, const WalletLocation& location, bilingual_str& error_string, std::vector<bilingual_str>& warnings);
|
||||
|
||||
/* Initializes the wallet, returns a new CWallet instance or a null pointer in case of an error */
|
||||
static std::shared_ptr<CWallet> CreateWalletFromFile(interfaces::Chain& chain, const WalletLocation& location, bilingual_str& error, std::vector<bilingual_str>& warnings, uint64_t wallet_creation_flags = 0);
|
||||
static std::shared_ptr<CWallet> Create(interfaces::Chain& chain, const std::string& name, std::unique_ptr<WalletDatabase> database, uint64_t wallet_creation_flags, bilingual_str& error, std::vector<bilingual_str>& warnings);
|
||||
|
||||
/**
|
||||
* Wallet post-init setup
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@
|
|||
#include <util/bip32.h>
|
||||
#include <util/system.h>
|
||||
#include <util/time.h>
|
||||
#include <util/translation.h>
|
||||
#include <wallet/bdb.h>
|
||||
#include <wallet/wallet.h>
|
||||
|
||||
#include <atomic>
|
||||
|
|
@ -1080,16 +1082,41 @@ bool WalletBatch::TxnAbort()
|
|||
return m_batch->TxnAbort();
|
||||
}
|
||||
|
||||
bool IsWalletLoaded(const fs::path& wallet_path)
|
||||
std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error)
|
||||
{
|
||||
return IsBDBWalletLoaded(wallet_path);
|
||||
}
|
||||
bool exists;
|
||||
try {
|
||||
exists = fs::symlink_status(path).type() != fs::file_not_found;
|
||||
} catch (const fs::filesystem_error& e) {
|
||||
error = Untranslated(strprintf("Failed to access database path '%s': %s", path.string(), fsbridge::get_filesystem_error_message(e)));
|
||||
status = DatabaseStatus::FAILED_BAD_PATH;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/** Return object for accessing database at specified path. */
|
||||
std::unique_ptr<WalletDatabase> CreateWalletDatabase(const fs::path& path)
|
||||
{
|
||||
std::string filename;
|
||||
return MakeUnique<BerkeleyDatabase>(GetWalletEnv(path, filename), std::move(filename));
|
||||
Optional<DatabaseFormat> format;
|
||||
if (exists) {
|
||||
if (ExistsBerkeleyDatabase(path)) {
|
||||
format = DatabaseFormat::BERKELEY;
|
||||
}
|
||||
} else if (options.require_existing) {
|
||||
error = Untranslated(strprintf("Failed to load database path '%s'. Path does not exist.", path.string()));
|
||||
status = DatabaseStatus::FAILED_NOT_FOUND;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!format && options.require_existing) {
|
||||
error = Untranslated(strprintf("Failed to load database path '%s'. Data is not in recognized format.", path.string()));
|
||||
status = DatabaseStatus::FAILED_BAD_FORMAT;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (format && options.require_create) {
|
||||
error = Untranslated(strprintf("Failed to create database path '%s'. Database already exists.", path.string()));
|
||||
status = DatabaseStatus::FAILED_ALREADY_EXISTS;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return MakeBerkeleyDatabase(path, options, status, error);
|
||||
}
|
||||
|
||||
/** Return object for accessing dummy database with no read/write capabilities. */
|
||||
|
|
|
|||
|
|
@ -293,12 +293,6 @@ using KeyFilterFn = std::function<bool(const std::string&)>;
|
|||
//! Unserialize a given Key-Value pair and load it into the wallet
|
||||
bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, std::string& strType, std::string& strErr, const KeyFilterFn& filter_fn = nullptr);
|
||||
|
||||
/** Return whether a wallet database is currently loaded. */
|
||||
bool IsWalletLoaded(const fs::path& wallet_path);
|
||||
|
||||
/** Return object for accessing database at specified path. */
|
||||
std::unique_ptr<WalletDatabase> CreateWalletDatabase(const fs::path& path);
|
||||
|
||||
/** Return object for accessing dummy database with no read/write capabilities. */
|
||||
std::unique_ptr<WalletDatabase> CreateDummyWalletDatabase();
|
||||
|
||||
|
|
|
|||
|
|
@ -21,21 +21,9 @@ static void WalletToolReleaseWallet(CWallet* wallet)
|
|||
delete wallet;
|
||||
}
|
||||
|
||||
static std::shared_ptr<CWallet> CreateWallet(const std::string& name, const fs::path& path)
|
||||
static void WalletCreate(CWallet* wallet_instance)
|
||||
{
|
||||
if (fs::exists(path)) {
|
||||
tfm::format(std::cerr, "Error: File exists already\n");
|
||||
return nullptr;
|
||||
}
|
||||
// dummy chain interface
|
||||
std::shared_ptr<CWallet> wallet_instance(new CWallet(nullptr /* chain */, WalletLocation(name), CreateWalletDatabase(path)), WalletToolReleaseWallet);
|
||||
LOCK(wallet_instance->cs_wallet);
|
||||
bool first_run = true;
|
||||
DBErrors load_wallet_ret = wallet_instance->LoadWallet(first_run);
|
||||
if (load_wallet_ret != DBErrors::LOAD_OK) {
|
||||
tfm::format(std::cerr, "Error creating %s", name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
wallet_instance->SetMinVersion(FEATURE_HD_SPLIT);
|
||||
|
||||
|
|
@ -46,18 +34,26 @@ static std::shared_ptr<CWallet> CreateWallet(const std::string& name, const fs::
|
|||
|
||||
tfm::format(std::cout, "Topping up keypool...\n");
|
||||
wallet_instance->TopUpKeyPool();
|
||||
return wallet_instance;
|
||||
}
|
||||
|
||||
static std::shared_ptr<CWallet> LoadWallet(const std::string& name, const fs::path& path)
|
||||
static std::shared_ptr<CWallet> MakeWallet(const std::string& name, const fs::path& path, bool create)
|
||||
{
|
||||
if (!fs::exists(path)) {
|
||||
tfm::format(std::cerr, "Error: Wallet files does not exist\n");
|
||||
DatabaseOptions options;
|
||||
DatabaseStatus status;
|
||||
if (create) {
|
||||
options.require_create = true;
|
||||
} else {
|
||||
options.require_existing = true;
|
||||
}
|
||||
bilingual_str error;
|
||||
std::unique_ptr<WalletDatabase> database = MakeDatabase(path, options, status, error);
|
||||
if (!database) {
|
||||
tfm::format(std::cerr, "%s\n", error.original);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// dummy chain interface
|
||||
std::shared_ptr<CWallet> wallet_instance(new CWallet(nullptr /* chain */, WalletLocation(name), CreateWalletDatabase(path)), WalletToolReleaseWallet);
|
||||
std::shared_ptr<CWallet> wallet_instance{new CWallet(nullptr /* chain */, name, std::move(database)), WalletToolReleaseWallet};
|
||||
DBErrors load_wallet_ret;
|
||||
try {
|
||||
bool first_run;
|
||||
|
|
@ -89,6 +85,8 @@ static std::shared_ptr<CWallet> LoadWallet(const std::string& name, const fs::pa
|
|||
}
|
||||
}
|
||||
|
||||
if (create) WalletCreate(wallet_instance.get());
|
||||
|
||||
return wallet_instance;
|
||||
}
|
||||
|
||||
|
|
@ -109,19 +107,14 @@ bool ExecuteWalletToolFunc(const std::string& command, const std::string& name)
|
|||
fs::path path = fs::absolute(name, GetWalletDir());
|
||||
|
||||
if (command == "create") {
|
||||
std::shared_ptr<CWallet> wallet_instance = CreateWallet(name, path);
|
||||
std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, /* create= */ true);
|
||||
if (wallet_instance) {
|
||||
WalletShowInfo(wallet_instance.get());
|
||||
wallet_instance->Close();
|
||||
}
|
||||
} else if (command == "info" || command == "salvage") {
|
||||
if (!fs::exists(path)) {
|
||||
tfm::format(std::cerr, "Error: no wallet file at %s\n", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (command == "info") {
|
||||
std::shared_ptr<CWallet> wallet_instance = LoadWallet(name, path);
|
||||
std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, /* create= */ false);
|
||||
if (!wallet_instance) return false;
|
||||
WalletShowInfo(wallet_instance.get());
|
||||
wallet_instance->Close();
|
||||
|
|
|
|||
|
|
@ -9,8 +9,6 @@
|
|||
|
||||
namespace WalletTool {
|
||||
|
||||
std::shared_ptr<CWallet> CreateWallet(const std::string& name, const fs::path& path);
|
||||
std::shared_ptr<CWallet> LoadWallet(const std::string& name, const fs::path& path);
|
||||
void WalletShowInfo(CWallet* wallet_instance);
|
||||
bool ExecuteWalletToolFunc(const std::string& command, const std::string& file);
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ fs::path GetWalletDir()
|
|||
return path;
|
||||
}
|
||||
|
||||
static bool IsBerkeleyBtree(const fs::path& path)
|
||||
bool IsBerkeleyBtree(const fs::path& path)
|
||||
{
|
||||
if (!fs::exists(path)) return false;
|
||||
|
||||
|
|
@ -91,19 +91,3 @@ std::vector<fs::path> ListWalletDir()
|
|||
|
||||
return paths;
|
||||
}
|
||||
|
||||
WalletLocation::WalletLocation(const std::string& name)
|
||||
: m_name(name)
|
||||
, m_path(fs::absolute(name, GetWalletDir()))
|
||||
{
|
||||
}
|
||||
|
||||
bool WalletLocation::Exists() const
|
||||
{
|
||||
fs::path path = m_path;
|
||||
// For the default wallet, check specifically for the wallet.dat file
|
||||
if (m_name.empty()) {
|
||||
path = fs::absolute("wallet.dat", m_path);
|
||||
}
|
||||
return fs::symlink_status(path).type() != fs::file_not_found;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,26 +67,6 @@ fs::path GetWalletDir();
|
|||
//! Get wallets in wallet directory.
|
||||
std::vector<fs::path> ListWalletDir();
|
||||
|
||||
//! The WalletLocation class provides wallet information.
|
||||
class WalletLocation final
|
||||
{
|
||||
std::string m_name;
|
||||
fs::path m_path;
|
||||
|
||||
public:
|
||||
explicit WalletLocation() {}
|
||||
explicit WalletLocation(const std::string& name);
|
||||
|
||||
//! Get wallet name.
|
||||
const std::string& GetName() const { return m_name; }
|
||||
|
||||
//! Get wallet absolute path.
|
||||
const fs::path& GetPath() const { return m_path; }
|
||||
|
||||
//! Return whether the wallet exists.
|
||||
bool Exists() const;
|
||||
};
|
||||
|
||||
/** Descriptor with some wallet metadata */
|
||||
class WalletDescriptor
|
||||
{
|
||||
|
|
|
|||
|
|
@ -129,7 +129,8 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
|
|||
try:
|
||||
node1.loadwallet('wmulti')
|
||||
except JSONRPCException as e:
|
||||
if e.error['code'] == -18 and 'Wallet wmulti not found' in e.error['message']:
|
||||
path = os.path.join(self.options.tmpdir, "node1", "elementsregtest", "wallets", "wmulti")
|
||||
if e.error['code'] == -18 and "Wallet file verification failed. Failed to load database path '{}'. Path does not exist.".format(path) in e.error['message']:
|
||||
node1.createwallet(wallet_name='wmulti', disable_private_keys=True)
|
||||
else:
|
||||
raise
|
||||
|
|
|
|||
|
|
@ -70,12 +70,14 @@ class ToolWalletTest(BitcoinTestFramework):
|
|||
self.assert_raises_tool_error('Invalid command: help', 'help')
|
||||
self.assert_raises_tool_error('Error: two methods provided (info and create). Only one method should be provided.', 'info', 'create')
|
||||
self.assert_raises_tool_error('Error parsing command line arguments: Invalid parameter -foo', '-foo')
|
||||
locked_dir = os.path.join(self.options.tmpdir, "node0", "elementsregtest", "wallets")
|
||||
self.assert_raises_tool_error(
|
||||
'Error loading wallet.dat. Is wallet being used by another process?',
|
||||
'Error initializing wallet database environment "{}"!'.format(locked_dir),
|
||||
'-wallet=wallet.dat',
|
||||
'info',
|
||||
)
|
||||
self.assert_raises_tool_error('Error: no wallet file at nonexistent.dat', '-wallet=nonexistent.dat', 'info')
|
||||
path = os.path.join(self.options.tmpdir, "node0", "elementsregtest", "wallets", "nonexistent.dat")
|
||||
self.assert_raises_tool_error("Failed to load database path '{}'. Path does not exist.".format(path), '-wallet=nonexistent.dat', 'info')
|
||||
|
||||
def test_tool_wallet_info(self):
|
||||
# Stop the node to close the wallet to call the info command.
|
||||
|
|
|
|||
|
|
@ -244,13 +244,16 @@ class MultiWalletTest(BitcoinTestFramework):
|
|||
assert_equal(set(self.nodes[0].listwallets()), set(wallet_names))
|
||||
|
||||
# Fail to load if wallet doesn't exist
|
||||
assert_raises_rpc_error(-18, 'Wallet wallets not found.', self.nodes[0].loadwallet, 'wallets')
|
||||
path = os.path.join(self.options.tmpdir, "node0", "elementsregtest", "wallets", "wallets")
|
||||
assert_raises_rpc_error(-18, "Wallet file verification failed. Failed to load database path '{}'. Path does not exist.".format(path), self.nodes[0].loadwallet, 'wallets')
|
||||
|
||||
# Fail to load duplicate wallets
|
||||
assert_raises_rpc_error(-4, 'Wallet file verification failed. Error loading wallet w1. Duplicate -wallet filename specified.', self.nodes[0].loadwallet, wallet_names[0])
|
||||
path = os.path.join(self.options.tmpdir, "node0", "elementsregtest", "wallets", "w1", "wallet.dat")
|
||||
assert_raises_rpc_error(-4, "Wallet file verification failed. Refusing to load database. Data file '{}' is already loaded.".format(path), self.nodes[0].loadwallet, wallet_names[0])
|
||||
|
||||
# Fail to load duplicate wallets by different ways (directory and filepath)
|
||||
assert_raises_rpc_error(-4, "Wallet file verification failed. Error loading wallet wallet.dat. Duplicate -wallet filename specified.", self.nodes[0].loadwallet, 'wallet.dat')
|
||||
path = os.path.join(self.options.tmpdir, "node0", "elementsregtest", "wallets", "wallet.dat")
|
||||
assert_raises_rpc_error(-4, "Wallet file verification failed. Refusing to load database. Data file '{}' is already loaded.".format(path), self.nodes[0].loadwallet, 'wallet.dat')
|
||||
|
||||
# Fail to load if one wallet is a copy of another
|
||||
assert_raises_rpc_error(-4, "BerkeleyDatabase: Can't open database w8_copy (duplicates fileid", self.nodes[0].loadwallet, 'w8_copy')
|
||||
|
|
@ -264,12 +267,14 @@ class MultiWalletTest(BitcoinTestFramework):
|
|||
|
||||
# Fail to load if a directory is specified that doesn't contain a wallet
|
||||
os.mkdir(wallet_dir('empty_wallet_dir'))
|
||||
assert_raises_rpc_error(-18, "Directory empty_wallet_dir does not contain a wallet.dat file", self.nodes[0].loadwallet, 'empty_wallet_dir')
|
||||
path = os.path.join(self.options.tmpdir, "node0", "elementsregtest", "wallets", "empty_wallet_dir")
|
||||
assert_raises_rpc_error(-18, "Wallet file verification failed. Failed to load database path '{}'. Data is not in recognized format.".format(path), self.nodes[0].loadwallet, 'empty_wallet_dir')
|
||||
|
||||
self.log.info("Test dynamic wallet creation.")
|
||||
|
||||
# Fail to create a wallet if it already exists.
|
||||
assert_raises_rpc_error(-4, "Wallet w2 already exists.", self.nodes[0].createwallet, 'w2')
|
||||
path = os.path.join(self.options.tmpdir, "node0", "elementsregtest", "wallets", "w2")
|
||||
assert_raises_rpc_error(-4, "Failed to create database path '{}'. Database already exists.".format(path), self.nodes[0].createwallet, 'w2')
|
||||
|
||||
# Successfully create a wallet with a new name
|
||||
loadwallet_name = self.nodes[0].createwallet('w9')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue