LCOV - code coverage report
Current view: top level - src - addrdb.cpp (source / functions) Coverage Total Hit
Test: fuzz_coverage.info Lines: 29.1 % 127 37
Test Date: 2025-07-04 04:08:43 Functions: 29.4 % 17 5
Branches: 16.2 % 222 36

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2009-2010 Satoshi Nakamoto
       2                 :             : // Copyright (c) 2009-2022 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 <bitcoin-build-config.h> // IWYU pragma: keep
       7                 :             : 
       8                 :             : #include <addrdb.h>
       9                 :             : 
      10                 :             : #include <addrman.h>
      11                 :             : #include <chainparams.h>
      12                 :             : #include <clientversion.h>
      13                 :             : #include <common/args.h>
      14                 :             : #include <common/settings.h>
      15                 :             : #include <cstdint>
      16                 :             : #include <hash.h>
      17                 :             : #include <logging.h>
      18                 :             : #include <logging/timer.h>
      19                 :             : #include <netbase.h>
      20                 :             : #include <netgroup.h>
      21                 :             : #include <random.h>
      22                 :             : #include <streams.h>
      23                 :             : #include <tinyformat.h>
      24                 :             : #include <univalue.h>
      25                 :             : #include <util/fs.h>
      26                 :             : #include <util/fs_helpers.h>
      27                 :             : #include <util/syserror.h>
      28                 :             : #include <util/translation.h>
      29                 :             : 
      30                 :             : namespace {
      31                 :             : 
      32                 :           0 : class DbNotFoundError : public std::exception
      33                 :             : {
      34                 :             :     using std::exception::exception;
      35                 :             : };
      36                 :             : 
      37                 :             : template <typename Stream, typename Data>
      38                 :           0 : bool SerializeDB(Stream& stream, const Data& data)
      39                 :             : {
      40                 :             :     // Write and commit header, data
      41                 :             :     try {
      42         [ #  # ]:           0 :         HashedSourceWriter hashwriter{stream};
      43   [ #  #  #  #  :           0 :         hashwriter << Params().MessageStart() << data;
                   #  # ]
      44         [ #  # ]:           0 :         stream << hashwriter.GetHash();
      45         [ -  - ]:           0 :     } catch (const std::exception& e) {
      46         [ -  - ]:           0 :         LogError("%s: Serialize or I/O error - %s\n", __func__, e.what());
      47                 :             :         return false;
      48                 :             :     }
      49                 :             : 
      50                 :             :     return true;
      51                 :             : }
      52                 :             : 
      53                 :             : template <typename Data>
      54                 :           0 : bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data& data)
      55                 :             : {
      56                 :             :     // Generate random temporary filename
      57                 :           0 :     const uint16_t randv{FastRandomContext().rand<uint16_t>()};
      58                 :           0 :     std::string tmpfn = strprintf("%s.%04x", prefix, randv);
      59                 :             : 
      60                 :             :     // open temp output file
      61   [ #  #  #  # ]:           0 :     fs::path pathTmp = gArgs.GetDataDirNet() / fs::u8path(tmpfn);
      62         [ #  # ]:           0 :     FILE *file = fsbridge::fopen(pathTmp, "wb");
      63   [ #  #  #  # ]:           0 :     AutoFile fileout{file};
      64         [ #  # ]:           0 :     if (fileout.IsNull()) {
      65         [ #  # ]:           0 :         remove(pathTmp);
      66         [ #  # ]:           0 :         LogError("%s: Failed to open file %s\n", __func__, fs::PathToString(pathTmp));
      67                 :           0 :         return false;
      68                 :             :     }
      69                 :             : 
      70                 :             :     // Serialize
      71   [ #  #  #  # ]:           0 :     if (!SerializeDB(fileout, data)) {
      72         [ #  # ]:           0 :         (void)fileout.fclose();
      73         [ #  # ]:           0 :         remove(pathTmp);
      74                 :             :         return false;
      75                 :             :     }
      76   [ #  #  #  # ]:           0 :     if (!fileout.Commit()) {
      77         [ #  # ]:           0 :         (void)fileout.fclose();
      78         [ #  # ]:           0 :         remove(pathTmp);
      79         [ #  # ]:           0 :         LogError("%s: Failed to flush file %s\n", __func__, fs::PathToString(pathTmp));
      80                 :           0 :         return false;
      81                 :             :     }
      82   [ #  #  #  # ]:           0 :     if (fileout.fclose() != 0) {
      83                 :           0 :         const int errno_save{errno};
      84         [ #  # ]:           0 :         remove(pathTmp);
      85   [ #  #  #  # ]:           0 :         LogError("Failed to close file %s after commit: %s", fs::PathToString(pathTmp), SysErrorString(errno_save));
      86                 :           0 :         return false;
      87                 :             :     }
      88                 :             : 
      89                 :             :     // replace existing file, if any, with new file
      90   [ #  #  #  #  :           0 :     if (!RenameOver(pathTmp, path)) {
                   #  # ]
      91         [ #  # ]:           0 :         remove(pathTmp);
      92         [ #  # ]:           0 :         LogError("%s: Rename-into-place failed\n", __func__);
      93                 :             :         return false;
      94                 :             :     }
      95                 :             : 
      96                 :             :     return true;
      97                 :           0 : }
      98                 :             : 
      99                 :             : template <typename Stream, typename Data>
     100                 :        1487 : void DeserializeDB(Stream& stream, Data&& data, bool fCheckSum = true)
     101                 :             : {
     102                 :        1487 :     HashVerifier verifier{stream};
     103                 :             :     // de-serialize file header (network specific magic number) and ..
     104                 :             :     MessageStartChars pchMsgTmp;
     105                 :        1400 :     verifier >> pchMsgTmp;
     106                 :             :     // ... verify the network matches ours
     107         [ +  + ]:        1400 :     if (pchMsgTmp != Params().MessageStart()) {
     108         [ +  - ]:           7 :         throw std::runtime_error{"Invalid network magic number"};
     109                 :             :     }
     110                 :             : 
     111                 :             :     // de-serialize data
     112                 :         599 :     verifier >> data;
     113                 :             : 
     114                 :             :     // verify checksum
     115         [ -  + ]:         599 :     if (fCheckSum) {
     116                 :           0 :         uint256 hashTmp;
     117                 :           0 :         stream >> hashTmp;
     118         [ #  # ]:           0 :         if (hashTmp != verifier.GetHash()) {
     119         [ #  # ]:           0 :             throw std::runtime_error{"Checksum mismatch, data corrupted"};
     120                 :             :         }
     121                 :             :     }
     122                 :         599 : }
     123                 :             : 
     124                 :             : template <typename Data>
     125                 :           0 : void DeserializeFileDB(const fs::path& path, Data&& data)
     126                 :             : {
     127                 :           0 :     FILE* file = fsbridge::fopen(path, "rb");
     128   [ #  #  #  # ]:           0 :     AutoFile filein{file};
     129         [ #  # ]:           0 :     if (filein.IsNull()) {
     130                 :           0 :         throw DbNotFoundError{};
     131                 :             :     }
     132         [ #  # ]:           0 :     DeserializeDB(filein, data);
     133                 :           0 : }
     134                 :             : } // namespace
     135                 :             : 
     136                 :        3065 : CBanDB::CBanDB(fs::path ban_list_path)
     137   [ +  -  +  - ]:        9195 :     : m_banlist_dat(ban_list_path + ".dat"),
     138         [ +  - ]:        6130 :       m_banlist_json(ban_list_path + ".json")
     139                 :             : {
     140                 :        3065 : }
     141                 :             : 
     142                 :       25660 : bool CBanDB::Write(const banmap_t& banSet)
     143                 :             : {
     144                 :       25660 :     std::vector<std::string> errors;
     145   [ +  -  +  -  :       76980 :     if (common::WriteSettings(m_banlist_json, {{JSON_KEY, BanMapToJson(banSet)}}, errors)) {
          +  -  +  +  +  
                +  -  - ]
     146                 :             :         return true;
     147                 :             :     }
     148                 :             : 
     149         [ +  + ]:       12180 :     for (const auto& err : errors) {
     150         [ +  - ]:        6090 :         LogError("%s\n", err);
     151                 :             :     }
     152                 :             :     return false;
     153         [ +  - ]:       51320 : }
     154                 :             : 
     155                 :        3065 : bool CBanDB::Read(banmap_t& banSet)
     156                 :             : {
     157         [ -  + ]:        3065 :     if (fs::exists(m_banlist_dat)) {
     158         [ #  # ]:           0 :         LogPrintf("banlist.dat ignored because it can only be read by " CLIENT_NAME " version 22.x. Remove %s to silence this warning.\n", fs::quoted(fs::PathToString(m_banlist_dat)));
     159                 :             :     }
     160                 :             :     // If the JSON banlist does not exist, then recreate it
     161         [ +  + ]:        3065 :     if (!fs::exists(m_banlist_json)) {
     162                 :             :         return false;
     163                 :             :     }
     164                 :             : 
     165         [ +  - ]:        2526 :     std::map<std::string, common::SettingsValue> settings;
     166                 :        2526 :     std::vector<std::string> errors;
     167                 :             : 
     168   [ +  -  +  + ]:        2526 :     if (!common::ReadSettings(m_banlist_json, settings, errors)) {
     169         [ +  + ]:        1350 :         for (const auto& err : errors) {
     170   [ +  -  +  - ]:        2025 :             LogPrintf("Cannot load banlist %s: %s\n", fs::PathToString(m_banlist_json), err);
     171                 :             :         }
     172                 :             :         return false;
     173                 :             :     }
     174                 :             : 
     175                 :        1851 :     try {
     176   [ +  -  +  -  :        2003 :         BanMapFromJson(settings[JSON_KEY], banSet);
                   +  + ]
     177         [ -  + ]:         152 :     } catch (const std::runtime_error& e) {
     178   [ +  -  +  - ]:         304 :         LogPrintf("Cannot parse banlist %s: %s\n", fs::PathToString(m_banlist_json), e.what());
     179                 :         152 :         return false;
     180                 :         152 :     }
     181                 :             : 
     182                 :        1699 :     return true;
     183                 :        2526 : }
     184                 :             : 
     185                 :           0 : bool DumpPeerAddresses(const ArgsManager& args, const AddrMan& addr)
     186                 :             : {
     187         [ #  # ]:           0 :     const auto pathAddr = args.GetDataDirNet() / "peers.dat";
     188   [ #  #  #  # ]:           0 :     return SerializeFileDB("peers", pathAddr, addr);
     189                 :           0 : }
     190                 :             : 
     191                 :        1487 : void ReadFromStream(AddrMan& addr, DataStream& ssPeers)
     192                 :             : {
     193                 :        1487 :     DeserializeDB(ssPeers, addr, false);
     194                 :         599 : }
     195                 :             : 
     196                 :           0 : util::Result<std::unique_ptr<AddrMan>> LoadAddrman(const NetGroupManager& netgroupman, const ArgsManager& args)
     197                 :             : {
     198   [ #  #  #  # ]:           0 :     auto check_addrman = std::clamp<int32_t>(args.GetIntArg("-checkaddrman", DEFAULT_ADDRMAN_CONSISTENCY_CHECKS), 0, 1000000);
     199         [ #  # ]:           0 :     bool deterministic = HasTestOption(args, "addrman"); // use a deterministic addrman only for tests
     200                 :             : 
     201                 :           0 :     auto addrman{std::make_unique<AddrMan>(netgroupman, deterministic, /*consistency_check_ratio=*/check_addrman)};
     202                 :             : 
     203                 :           0 :     const auto start{SteadyClock::now()};
     204   [ #  #  #  # ]:           0 :     const auto path_addr{args.GetDataDirNet() / "peers.dat"};
     205                 :           0 :     try {
     206         [ #  # ]:           0 :         DeserializeFileDB(path_addr, *addrman);
     207   [ #  #  #  # ]:           0 :         LogPrintf("Loaded %i addresses from peers.dat  %dms\n", addrman->Size(), Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
     208   [ -  -  -  - ]:           0 :     } catch (const DbNotFoundError&) {
     209                 :             :         // Addrman can be in an inconsistent state after failure, reset it
     210         [ -  - ]:           0 :         addrman = std::make_unique<AddrMan>(netgroupman, deterministic, /*consistency_check_ratio=*/check_addrman);
     211   [ -  -  -  - ]:           0 :         LogPrintf("Creating peers.dat because the file was not found (%s)\n", fs::quoted(fs::PathToString(path_addr)));
     212         [ -  - ]:           0 :         DumpPeerAddresses(args, *addrman);
     213         [ -  - ]:           0 :     } catch (const InvalidAddrManVersionError&) {
     214   [ -  -  -  -  :           0 :         if (!RenameOver(path_addr, (fs::path)path_addr + ".bak")) {
          -  -  -  -  -  
                      - ]
     215         [ -  - ]:           0 :             return util::Error{strprintf(_("Failed to rename invalid peers.dat file. Please move or delete it and try again."))};
     216                 :             :         }
     217                 :             :         // Addrman can be in an inconsistent state after failure, reset it
     218         [ -  - ]:           0 :         addrman = std::make_unique<AddrMan>(netgroupman, deterministic, /*consistency_check_ratio=*/check_addrman);
     219   [ -  -  -  - ]:           0 :         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)));
     220         [ -  - ]:           0 :         DumpPeerAddresses(args, *addrman);
     221   [ -  -  -  - ]:           0 :     } catch (const std::exception& e) {
     222         [ -  - ]:           0 :         return util::Error{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."),
     223         [ -  - ]:           0 :                                      e.what(), CLIENT_BUGREPORT, fs::quoted(fs::PathToString(path_addr)))};
     224                 :           0 :     }
     225                 :           0 :     return addrman;
     226                 :           0 : }
     227                 :             : 
     228                 :           0 : void DumpAnchors(const fs::path& anchors_db_path, const std::vector<CAddress>& anchors)
     229                 :             : {
     230   [ #  #  #  # ]:           0 :     LOG_TIME_SECONDS(strprintf("Flush %d outbound block-relay-only peer addresses to anchors.dat", anchors.size()));
     231   [ #  #  #  # ]:           0 :     SerializeFileDB("anchors", anchors_db_path, CAddress::V2_DISK(anchors));
     232                 :           0 : }
     233                 :             : 
     234                 :           0 : std::vector<CAddress> ReadAnchors(const fs::path& anchors_db_path)
     235                 :             : {
     236                 :           0 :     std::vector<CAddress> anchors;
     237                 :           0 :     try {
     238         [ #  # ]:           0 :         DeserializeFileDB(anchors_db_path, CAddress::V2_DISK(anchors));
     239   [ #  #  #  # ]:           0 :         LogPrintf("Loaded %i addresses from %s\n", anchors.size(), fs::quoted(fs::PathToString(anchors_db_path.filename())));
     240         [ -  - ]:           0 :     } catch (const std::exception&) {
     241                 :           0 :         anchors.clear();
     242                 :           0 :     }
     243                 :             : 
     244         [ #  # ]:           0 :     fs::remove(anchors_db_path);
     245                 :           0 :     return anchors;
     246                 :           0 : }
        

Generated by: LCOV version 2.0-1