Inside Bitcoin
Opening the selected file…
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2020-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <wallet/dump.h>7#include <common/args.h>8#include <util/fs.h>9#include <util/translation.h>10#include <wallet/wallet.h>11#include <wallet/walletdb.h>13#include <algorithm>14#include <fstream>15#include <memory>16#include <string>17#include <utility>18#include <vector>20namespace wallet {21static const std::string DUMP_MAGIC = "BITCOIN_CORE_WALLET_DUMP";22uint32_t DUMP_VERSION = 1;24bool DumpWallet(const ArgsManager& args, WalletDatabase& db, bilingual_str& error)25{26// Get the dumpfile27std::string dump_filename = args.GetArg("-dumpfile", "");28if (dump_filename.empty()) {29error = _("No dump file provided. To use dump, -dumpfile=<filename> must be provided.");30return false;31}33fs::path path = fs::PathFromString(dump_filename);34path = fs::absolute(path);35if (fs::exists(path)) {36error = strprintf(_("File %s already exists. If you are sure this is what you want, move it out of the way first."), fs::PathToString(path));37return false;38}39std::ofstream dump_file;40dump_file.open(path.std_path());41if (dump_file.fail()) {42error = strprintf(_("Unable to open %s for writing"), fs::PathToString(path));43return false;44}46HashWriter hasher{};48std::unique_ptr<DatabaseBatch> batch = db.MakeBatch();50bool ret = true;51std::unique_ptr<DatabaseCursor> cursor = batch->GetNewCursor();52if (!cursor) {53error = _("Error: Couldn't create cursor into database");54ret = false;55}57// Write out a magic string with version58std::string line = strprintf("%s,%u\n", DUMP_MAGIC, DUMP_VERSION);59dump_file.write(line.data(), line.size());60hasher << std::span{line};62// Write out the file format63std::string format = db.Format();64// BDB files that are opened using BerkeleyRODatabase have its format as "bdb_ro"65// We want to override that format back to "bdb"66if (format == "bdb_ro") {67format = "bdb";68}69line = strprintf("%s,%s\n", "format", format);70dump_file.write(line.data(), line.size());71hasher << std::span{line};73if (ret) {75// Read the records76while (true) {77DataStream ss_key{};78DataStream ss_value{};79DatabaseCursor::Status status = cursor->Next(ss_key, ss_value);80if (status == DatabaseCursor::Status::DONE) {81ret = true;82break;83} else if (status == DatabaseCursor::Status::FAIL) {84error = _("Error reading next record from wallet database");85ret = false;86break;87}88std::string key_str = HexStr(ss_key);89std::string value_str = HexStr(ss_value);90line = strprintf("%s,%s\n", key_str, value_str);91dump_file.write(line.data(), line.size());92hasher << std::span{line};93}94}96cursor.reset();97batch.reset();99if (ret) {100// Write the hash101tfm::format(dump_file, "checksum,%s\n", HexStr(hasher.GetHash()));102dump_file.close();103} else {104// Remove the dumpfile on failure105dump_file.close();106fs::remove(path);107}109return ret;110}112// The standard wallet deleter function blocks on the validation interface113// queue, which doesn't exist for the bitcoin-wallet. Define our own114// deleter here.115static void WalletToolReleaseWallet(CWallet* wallet)116{117wallet->WalletLogPrintf("Releasing wallet\n");118wallet->Close();119delete wallet;120}122bool CreateFromDump(const ArgsManager& args, const std::string& name, const fs::path& wallet_path, bilingual_str& error)123{124if (name.empty()) {125tfm::format(std::cerr, "Wallet name cannot be empty\n");126return false;127}129// Get the dumpfile130std::string dump_filename = args.GetArg("-dumpfile", "");131if (dump_filename.empty()) {132error = _("No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided.");133return false;134}136fs::path dump_path = fs::PathFromString(dump_filename);137dump_path = fs::absolute(dump_path);138if (!fs::exists(dump_path)) {139error = strprintf(_("Dump file %s does not exist."), fs::PathToString(dump_path));140return false;141}142std::ifstream dump_file{dump_path.std_path()};144// Compute the checksum145HashWriter hasher{};146uint256 checksum;148// Check the magic and version149std::string magic_key;150std::getline(dump_file, magic_key, ',');151std::string version_value;152std::getline(dump_file, version_value, '\n');153if (magic_key != DUMP_MAGIC) {154error = strprintf(_("Error: Dumpfile identifier record is incorrect. Got \"%s\", expected \"%s\"."), magic_key, DUMP_MAGIC);155dump_file.close();156return false;157}158// Check the version number (value of first record)159const auto ver{ToIntegral<uint32_t>(version_value)};160if (!ver) {161error = strprintf(_("Error: Unable to parse version %u as a uint32_t"), version_value);162dump_file.close();163return false;164}165if (*ver != DUMP_VERSION) {166error = strprintf(_("Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s"), version_value);167dump_file.close();168return false;169}170std::string magic_hasher_line = strprintf("%s,%s\n", magic_key, version_value);171hasher << std::span{magic_hasher_line};173// Get the stored file format174std::string format_key;175std::getline(dump_file, format_key, ',');176std::string format_value;177std::getline(dump_file, format_value, '\n');178if (format_key != "format") {179error = strprintf(_("Error: Dumpfile format record is incorrect. Got \"%s\", expected \"format\"."), format_key);180dump_file.close();181return false;182}183// Make sure that the dump was created from a sqlite database only as that is the only184// type of database that we still support.185// Other formats such as BDB should not be loaded into a sqlite database since they also186// use a different type of wallet entirely which is no longer compatible with this software.187if (format_value != "sqlite") {188error = strprintf(_("Error: Dumpfile specifies an unsupported database format (%s). Only sqlite database dumps are supported"), format_value);189return false;190}191std::string format_hasher_line = strprintf("%s,%s\n", format_key, format_value);192hasher << std::span{format_hasher_line};194DatabaseOptions options;195DatabaseStatus status;196ReadDatabaseArgs(args, options);197options.require_create = true;198options.require_format = DatabaseFormat::SQLITE;199std::unique_ptr<WalletDatabase> database = MakeDatabase(wallet_path, options, status, error);200if (!database) return false;202// dummy chain interface203bool ret = true;204std::shared_ptr<CWallet> wallet(new CWallet(/*chain=*/nullptr, name, std::move(database)), WalletToolReleaseWallet);205{206// Get the database handle207WalletDatabase& db = wallet->GetDatabase();208std::unique_ptr<DatabaseBatch> batch = db.MakeBatch();209batch->TxnBegin();211// Read the records from the dump file and write them to the database212while (dump_file.good()) {213std::string key;214std::getline(dump_file, key, ',');215std::string value;216std::getline(dump_file, value, '\n');218if (key == "checksum") {219std::vector<unsigned char> parsed_checksum = ParseHex(value);220if (parsed_checksum.size() != checksum.size()) {221error = Untranslated("Error: Checksum is not the correct size");222ret = false;223break;224}225std::copy(parsed_checksum.begin(), parsed_checksum.end(), checksum.begin());226break;227}229std::string line = strprintf("%s,%s\n", key, value);230hasher << std::span{line};232if (key.empty() || value.empty()) {233continue;234}236if (!IsHex(key)) {237error = strprintf(_("Error: Got key that was not hex: %s"), key);238ret = false;239break;240}241if (!IsHex(value)) {242error = strprintf(_("Error: Got value that was not hex: %s"), value);243ret = false;244break;245}247std::vector<unsigned char> k = ParseHex(key);248std::vector<unsigned char> v = ParseHex(value);249if (!batch->Write(std::span{k}, std::span{v})) {250error = strprintf(_("Error: Unable to write record to new wallet"));