aboutsummaryrefslogtreecommitdiff
path: root/src/wallet/dump.cpp
blob: 0d82863de14d687f5e2113d4a814c7a19d067853 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// Copyright (c) 2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <wallet/dump.h>

#include <util/translation.h>
#include <wallet/wallet.h>

static const std::string DUMP_MAGIC = "BITCOIN_CORE_WALLET_DUMP";
uint32_t DUMP_VERSION = 1;

bool DumpWallet(CWallet& wallet, bilingual_str& error)
{
    // Get the dumpfile
    std::string dump_filename = gArgs.GetArg("-dumpfile", "");
    if (dump_filename.empty()) {
        error = _("No dump file provided. To use dump, -dumpfile=<filename> must be provided.");
        return false;
    }

    fs::path path = dump_filename;
    path = fs::absolute(path);
    if (fs::exists(path)) {
        error = strprintf(_("File %s already exists. If you are sure this is what you want, move it out of the way first."), path.string());
        return false;
    }
    fsbridge::ofstream dump_file;
    dump_file.open(path);
    if (dump_file.fail()) {
        error = strprintf(_("Unable to open %s for writing"), path.string());
        return false;
    }

    CHashWriter hasher(0, 0);

    WalletDatabase& db = wallet.GetDatabase();
    std::unique_ptr<DatabaseBatch> batch = db.MakeBatch();

    bool ret = true;
    if (!batch->StartCursor()) {
        error = _("Error: Couldn't create cursor into database");
        ret = false;
    }

    // Write out a magic string with version
    std::string line = strprintf("%s,%u\n", DUMP_MAGIC, DUMP_VERSION);
    dump_file.write(line.data(), line.size());
    hasher.write(line.data(), line.size());

    // Write out the file format
    line = strprintf("%s,%s\n", "format", db.Format());
    dump_file.write(line.data(), line.size());
    hasher.write(line.data(), line.size());

    if (ret) {

        // Read the records
        while (true) {
            CDataStream ss_key(SER_DISK, CLIENT_VERSION);
            CDataStream ss_value(SER_DISK, CLIENT_VERSION);
            bool complete;
            ret = batch->ReadAtCursor(ss_key, ss_value, complete);
            if (complete) {
                ret = true;
                break;
            } else if (!ret) {
                error = _("Error reading next record from wallet database");
                break;
            }
            std::string key_str = HexStr(ss_key);
            std::string value_str = HexStr(ss_value);
            line = strprintf("%s,%s\n", key_str, value_str);
            dump_file.write(line.data(), line.size());
            hasher.write(line.data(), line.size());
        }
    }

    batch->CloseCursor();
    batch.reset();

    // Close the wallet after we're done with it. The caller won't be doing this
    wallet.Close();

    if (ret) {
        // Write the hash
        tfm::format(dump_file, "checksum,%s\n", HexStr(hasher.GetHash()));
        dump_file.close();
    } else {
        // Remove the dumpfile on failure
        dump_file.close();
        fs::remove(path);
    }

    return ret;
}