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