LCOV - code coverage report
Current view: top level - src - addrdb.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 114 148 77.0 %
Date: 2022-04-21 14:51:19 Functions: 17 17 100.0 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 29 52 55.8 %

           Branch data     Line data    Source code
#       1                 :            : // Copyright (c) 2009-2010 Satoshi Nakamoto
#       2                 :            : // Copyright (c) 2009-2021 The Bitcoin Core developers
#       3                 :            : // Distributed under the MIT software license, see the accompanying
#       4                 :            : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#       5                 :            : 
#       6                 :            : #include <addrdb.h>
#       7                 :            : 
#       8                 :            : #include <addrman.h>
#       9                 :            : #include <chainparams.h>
#      10                 :            : #include <clientversion.h>
#      11                 :            : #include <cstdint>
#      12                 :            : #include <fs.h>
#      13                 :            : #include <hash.h>
#      14                 :            : #include <logging/timer.h>
#      15                 :            : #include <netbase.h>
#      16                 :            : #include <random.h>
#      17                 :            : #include <streams.h>
#      18                 :            : #include <tinyformat.h>
#      19                 :            : #include <univalue.h>
#      20                 :            : #include <util/settings.h>
#      21                 :            : #include <util/system.h>
#      22                 :            : #include <util/translation.h>
#      23                 :            : 
#      24                 :            : namespace {
#      25                 :            : 
#      26                 :            : class DbNotFoundError : public std::exception
#      27                 :            : {
#      28                 :            :     using std::exception::exception;
#      29                 :            : };
#      30                 :            : 
#      31                 :            : template <typename Stream, typename Data>
#      32                 :            : bool SerializeDB(Stream& stream, const Data& data)
#      33                 :       1165 : {
#      34                 :            :     // Write and commit header, data
#      35                 :       1165 :     try {
#      36                 :       1165 :         CHashWriter hasher(stream.GetType(), stream.GetVersion());
#      37                 :       1165 :         stream << Params().MessageStart() << data;
#      38                 :       1165 :         hasher << Params().MessageStart() << data;
#      39                 :       1165 :         stream << hasher.GetHash();
#      40                 :       1165 :     } catch (const std::exception& e) {
#      41                 :          0 :         return error("%s: Serialize or I/O error - %s", __func__, e.what());
#      42                 :          0 :     }
#      43                 :            : 
#      44                 :       1165 :     return true;
#      45                 :       1165 : }
#      46                 :            : 
#      47                 :            : template <typename Data>
#      48                 :            : bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data& data, int version)
#      49                 :       1165 : {
#      50                 :            :     // Generate random temporary filename
#      51                 :       1165 :     uint16_t randv = 0;
#      52                 :       1165 :     GetRandBytes((unsigned char*)&randv, sizeof(randv));
#      53                 :       1165 :     std::string tmpfn = strprintf("%s.%04x", prefix, randv);
#      54                 :            : 
#      55                 :            :     // open temp output file, and associate with CAutoFile
#      56                 :       1165 :     fs::path pathTmp = gArgs.GetDataDirNet() / tmpfn;
#      57                 :       1165 :     FILE *file = fsbridge::fopen(pathTmp, "wb");
#      58                 :       1165 :     CAutoFile fileout(file, SER_DISK, version);
#      59 [ -  + ][ -  + ]:       1165 :     if (fileout.IsNull()) {
#      60                 :          0 :         fileout.fclose();
#      61                 :          0 :         remove(pathTmp);
#      62                 :          0 :         return error("%s: Failed to open file %s", __func__, fs::PathToString(pathTmp));
#      63                 :          0 :     }
#      64                 :            : 
#      65                 :            :     // Serialize
#      66 [ -  + ][ -  + ]:       1165 :     if (!SerializeDB(fileout, data)) {
#      67                 :          0 :         fileout.fclose();
#      68                 :          0 :         remove(pathTmp);
#      69                 :          0 :         return false;
#      70                 :          0 :     }
#      71 [ -  + ][ -  + ]:       1165 :     if (!FileCommit(fileout.Get())) {
#      72                 :          0 :         fileout.fclose();
#      73                 :          0 :         remove(pathTmp);
#      74                 :          0 :         return error("%s: Failed to flush file %s", __func__, fs::PathToString(pathTmp));
#      75                 :          0 :     }
#      76                 :       1165 :     fileout.fclose();
#      77                 :            : 
#      78                 :            :     // replace existing file, if any, with new file
#      79 [ -  + ][ -  + ]:       1165 :     if (!RenameOver(pathTmp, path)) {
#      80                 :          0 :         remove(pathTmp);
#      81                 :          0 :         return error("%s: Rename-into-place failed", __func__);
#      82                 :          0 :     }
#      83                 :            : 
#      84                 :       1165 :     return true;
#      85                 :       1165 : }
#      86                 :            : 
#      87                 :            : template <typename Stream, typename Data>
#      88                 :            : void DeserializeDB(Stream& stream, Data& data, bool fCheckSum = true)
#      89                 :        359 : {
#      90                 :        359 :     CHashVerifier<Stream> verifier(&stream);
#      91                 :            :     // de-serialize file header (network specific magic number) and ..
#      92                 :        359 :     unsigned char pchMsgTmp[4];
#      93                 :        359 :     verifier >> pchMsgTmp;
#      94                 :            :     // ... verify the network matches ours
#      95 [ -  + ][ +  + ]:        359 :     if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp))) {
#                 [ -  + ]
#      96                 :          1 :         throw std::runtime_error{"Invalid network magic number"};
#      97                 :          1 :     }
#      98                 :            : 
#      99                 :            :     // de-serialize data
#     100                 :        358 :     verifier >> data;
#     101                 :            : 
#     102                 :            :     // verify checksum
#     103 [ -  + ][ +  + ]:        358 :     if (fCheckSum) {
#                 [ +  - ]
#     104                 :        349 :         uint256 hashTmp;
#     105                 :        349 :         stream >> hashTmp;
#     106 [ #  # ][ +  + ]:        349 :         if (hashTmp != verifier.GetHash()) {
#                 [ -  + ]
#     107                 :          1 :             throw std::runtime_error{"Checksum mismatch, data corrupted"};
#     108                 :          1 :         }
#     109                 :        349 :     }
#     110                 :        358 : }
#     111                 :            : 
#     112                 :            : template <typename Data>
#     113                 :            : void DeserializeFileDB(const fs::path& path, Data& data, int version)
#     114                 :        783 : {
#     115                 :            :     // open input file, and associate with CAutoFile
#     116                 :        783 :     FILE* file = fsbridge::fopen(path, "rb");
#     117                 :        783 :     CAutoFile filein(file, SER_DISK, version);
#     118 [ +  + ][ +  + ]:        783 :     if (filein.IsNull()) {
#     119                 :        428 :         throw DbNotFoundError{};
#     120                 :        428 :     }
#     121                 :        355 :     DeserializeDB(filein, data);
#     122                 :        355 : }
#     123                 :            : } // namespace
#     124                 :            : 
#     125                 :            : CBanDB::CBanDB(fs::path ban_list_path)
#     126                 :            :     : m_banlist_dat(ban_list_path + ".dat"),
#     127                 :            :       m_banlist_json(ban_list_path + ".json")
#     128                 :        964 : {
#     129                 :        964 : }
#     130                 :            : 
#     131                 :            : bool CBanDB::Write(const banmap_t& banSet)
#     132                 :        670 : {
#     133                 :        670 :     std::vector<std::string> errors;
#     134         [ +  - ]:        670 :     if (util::WriteSettings(m_banlist_json, {{JSON_KEY, BanMapToJson(banSet)}}, errors)) {
#     135                 :        670 :         return true;
#     136                 :        670 :     }
#     137                 :            : 
#     138         [ #  # ]:          0 :     for (const auto& err : errors) {
#     139                 :          0 :         error("%s", err);
#     140                 :          0 :     }
#     141                 :          0 :     return false;
#     142                 :        670 : }
#     143                 :            : 
#     144                 :            : bool CBanDB::Read(banmap_t& banSet)
#     145                 :        964 : {
#     146         [ -  + ]:        964 :     if (fs::exists(m_banlist_dat)) {
#     147                 :          0 :         LogPrintf("banlist.dat ignored because it can only be read by " PACKAGE_NAME " version 22.x. Remove %s to silence this warning.\n", fs::quoted(fs::PathToString(m_banlist_dat)));
#     148                 :          0 :     }
#     149                 :            :     // If the JSON banlist does not exist, then recreate it
#     150         [ +  + ]:        964 :     if (!fs::exists(m_banlist_json)) {
#     151                 :        623 :         return false;
#     152                 :        623 :     }
#     153                 :            : 
#     154                 :        341 :     std::map<std::string, util::SettingsValue> settings;
#     155                 :        341 :     std::vector<std::string> errors;
#     156                 :            : 
#     157         [ -  + ]:        341 :     if (!util::ReadSettings(m_banlist_json, settings, errors)) {
#     158         [ #  # ]:          0 :         for (const auto& err : errors) {
#     159                 :          0 :             LogPrintf("Cannot load banlist %s: %s\n", fs::PathToString(m_banlist_json), err);
#     160                 :          0 :         }
#     161                 :          0 :         return false;
#     162                 :          0 :     }
#     163                 :            : 
#     164                 :        341 :     try {
#     165                 :        341 :         BanMapFromJson(settings[JSON_KEY], banSet);
#     166                 :        341 :     } catch (const std::runtime_error& e) {
#     167                 :          0 :         LogPrintf("Cannot parse banlist %s: %s\n", fs::PathToString(m_banlist_json), e.what());
#     168                 :          0 :         return false;
#     169                 :          0 :     }
#     170                 :            : 
#     171                 :        341 :     return true;
#     172                 :        341 : }
#     173                 :            : 
#     174                 :            : bool DumpPeerAddresses(const ArgsManager& args, const AddrMan& addr)
#     175                 :       1146 : {
#     176                 :       1146 :     const auto pathAddr = args.GetDataDirNet() / "peers.dat";
#     177                 :       1146 :     return SerializeFileDB("peers", pathAddr, addr, CLIENT_VERSION);
#     178                 :       1146 : }
#     179                 :            : 
#     180                 :            : void ReadFromStream(AddrMan& addr, CDataStream& ssPeers)
#     181                 :          4 : {
#     182                 :          4 :     DeserializeDB(ssPeers, addr, false);
#     183                 :          4 : }
#     184                 :            : 
#     185                 :            : std::optional<bilingual_str> LoadAddrman(const std::vector<bool>& asmap, const ArgsManager& args, std::unique_ptr<AddrMan>& addrman)
#     186                 :        764 : {
#     187                 :        764 :     auto check_addrman = std::clamp<int32_t>(args.GetIntArg("-checkaddrman", DEFAULT_ADDRMAN_CONSISTENCY_CHECKS), 0, 1000000);
#     188                 :        764 :     addrman = std::make_unique<AddrMan>(asmap, /*deterministic=*/false, /*consistency_check_ratio=*/check_addrman);
#     189                 :            : 
#     190                 :        764 :     int64_t nStart = GetTimeMillis();
#     191                 :        764 :     const auto path_addr{args.GetDataDirNet() / "peers.dat"};
#     192                 :        764 :     try {
#     193                 :        764 :         DeserializeFileDB(path_addr, *addrman, CLIENT_VERSION);
#     194                 :        764 :         LogPrintf("Loaded %i addresses from peers.dat  %dms\n", addrman->size(), GetTimeMillis() - nStart);
#     195                 :        764 :     } catch (const DbNotFoundError&) {
#     196                 :            :         // Addrman can be in an inconsistent state after failure, reset it
#     197                 :        423 :         addrman = std::make_unique<AddrMan>(asmap, /*deterministic=*/false, /*consistency_check_ratio=*/check_addrman);
#     198                 :        423 :         LogPrintf("Creating peers.dat because the file was not found (%s)\n", fs::quoted(fs::PathToString(path_addr)));
#     199                 :        423 :         DumpPeerAddresses(args, *addrman);
#     200                 :        423 :     } catch (const InvalidAddrManVersionError&) {
#     201         [ -  + ]:          1 :         if (!RenameOver(path_addr, (fs::path)path_addr + ".bak")) {
#     202                 :          0 :             addrman = nullptr;
#     203                 :          0 :             return strprintf(_("Failed to rename invalid peers.dat file. Please move or delete it and try again."));
#     204                 :          0 :         }
#     205                 :            :         // Addrman can be in an inconsistent state after failure, reset it
#     206                 :          1 :         addrman = std::make_unique<AddrMan>(asmap, /*deterministic=*/false, /*consistency_check_ratio=*/check_addrman);
#     207                 :          1 :         LogPrintf("Creating new peers.dat because the file version was not compatible (%s). Original backed up to peers.dat.bak\n", fs::quoted(fs::PathToString(path_addr)));
#     208                 :          1 :         DumpPeerAddresses(args, *addrman);
#     209                 :          7 :     } catch (const std::exception& e) {
#     210                 :          7 :         addrman = nullptr;
#     211                 :          7 :         return strprintf(_("Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start."),
#     212                 :          7 :                          e.what(), PACKAGE_BUGREPORT, fs::quoted(fs::PathToString(path_addr)));
#     213                 :          7 :     }
#     214                 :        757 :     return std::nullopt;
#     215                 :        764 : }
#     216                 :            : 
#     217                 :            : void DumpAnchors(const fs::path& anchors_db_path, const std::vector<CAddress>& anchors)
#     218                 :         19 : {
#     219                 :         19 :     LOG_TIME_SECONDS(strprintf("Flush %d outbound block-relay-only peer addresses to anchors.dat", anchors.size()));
#     220                 :         19 :     SerializeFileDB("anchors", anchors_db_path, anchors, CLIENT_VERSION | ADDRV2_FORMAT);
#     221                 :         19 : }
#     222                 :            : 
#     223                 :            : std::vector<CAddress> ReadAnchors(const fs::path& anchors_db_path)
#     224                 :         19 : {
#     225                 :         19 :     std::vector<CAddress> anchors;
#     226                 :         19 :     try {
#     227                 :         19 :         DeserializeFileDB(anchors_db_path, anchors, CLIENT_VERSION | ADDRV2_FORMAT);
#     228                 :         19 :         LogPrintf("Loaded %i addresses from %s\n", anchors.size(), fs::quoted(fs::PathToString(anchors_db_path.filename())));
#     229                 :         19 :     } catch (const std::exception&) {
#     230                 :          5 :         anchors.clear();
#     231                 :          5 :     }
#     232                 :            : 
#     233                 :         19 :     fs::remove(anchors_db_path);
#     234                 :         19 :     return anchors;
#     235                 :         19 : }

Generated by: LCOV version 0-eol-96201-ge66f56f4af6a