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