utxo_snapshot.cpp raw
1 // Copyright (c) 2022-present The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5 #include <node/utxo_snapshot.h>
6
7 #include <streams.h>
8 #include <sync.h>
9 #include <tinyformat.h>
10 #include <uint256.h>
11 #include <util/fs.h>
12 #include <util/log.h>
13 #include <validation.h>
14
15 #include <cassert>
16 #include <cstdio>
17 #include <optional>
18 #include <string>
19
20 namespace node {
21
22 bool WriteSnapshotBaseBlockhash(Chainstate& snapshot_chainstate)
23 {
24 AssertLockHeld(::cs_main);
25 assert(snapshot_chainstate.m_from_snapshot_blockhash);
26
27 const std::optional<fs::path> chaindir = snapshot_chainstate.StoragePath();
28 assert(chaindir); // Sanity check that chainstate isn't in-memory.
29 const fs::path write_to = *chaindir / node::SNAPSHOT_BLOCKHASH_FILENAME;
30
31 FILE* file{fsbridge::fopen(write_to, "wb")};
32 AutoFile afile{file};
33 if (afile.IsNull()) {
34 LogError("[snapshot] failed to open base blockhash file for writing: %s",
35 fs::PathToString(write_to));
36 return false;
37 }
38 afile << *snapshot_chainstate.m_from_snapshot_blockhash;
39
40 if (afile.fclose() != 0) {
41 LogError("[snapshot] failed to close base blockhash file %s after writing",
42 fs::PathToString(write_to));
43 return false;
44 }
45 return true;
46 }
47
48 std::optional<uint256> ReadSnapshotBaseBlockhash(fs::path chaindir)
49 {
50 if (!fs::exists(chaindir)) {
51 LogWarning("[snapshot] cannot read base blockhash: no chainstate dir "
52 "exists at path %s", fs::PathToString(chaindir));
53 return std::nullopt;
54 }
55 const fs::path read_from = chaindir / node::SNAPSHOT_BLOCKHASH_FILENAME;
56 const std::string read_from_str = fs::PathToString(read_from);
57
58 if (!fs::exists(read_from)) {
59 LogWarning("[snapshot] snapshot chainstate dir is malformed! no base blockhash file "
60 "exists at path %s. Try deleting %s and calling loadtxoutset again?",
61 fs::PathToString(chaindir), read_from_str);
62 return std::nullopt;
63 }
64
65 uint256 base_blockhash;
66 FILE* file{fsbridge::fopen(read_from, "rb")};
67 AutoFile afile{file};
68 if (afile.IsNull()) {
69 LogWarning("[snapshot] failed to open base blockhash file for reading: %s",
70 read_from_str);
71 return std::nullopt;
72 }
73 afile >> base_blockhash;
74
75 int64_t position = afile.tell();
76 afile.seek(0, SEEK_END);
77 if (position != afile.tell()) {
78 LogWarning("[snapshot] unexpected trailing data in %s", read_from_str);
79 }
80 return base_blockhash;
81 }
82
83 std::optional<fs::path> FindAssumeutxoChainstateDir(const fs::path& data_dir)
84 {
85 fs::path possible_dir =
86 data_dir / fs::u8path(strprintf("chainstate%s", SNAPSHOT_CHAINSTATE_SUFFIX));
87
88 if (fs::exists(possible_dir)) {
89 return possible_dir;
90 }
91 return std::nullopt;
92 }
93
94 } // namespace node
95