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