// Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Copyright (c) 2016-2024 The Hush developers // Distributed under the GPLv3 software license, see the accompanying // file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html #include "addrdb.h" #include "addrman.h" #include "chainparams.h" #include "clientversion.h" #include "fs.h" #include "hash.h" #include "random.h" #include "streams.h" #include "tinyformat.h" #include "util.h" namespace { template bool SerializeDB(Stream& stream, const Data& data) { // Write and commit header, data try { CHashWriter hasher(stream.GetType(), stream.GetVersion()); stream << FLATDATA(Params().MessageStart()) << data; hasher << FLATDATA(Params().MessageStart()) << data; stream << hasher.GetHash(); } catch (const std::exception& e) { return error("%s: Serialize or I/O error - %s", __func__, e.what()); } return true; } template bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data& data) { // Generate random temporary filename unsigned short randv = 0; GetRandBytes((unsigned char*)&randv, sizeof(randv)); std::string tmpfn = strprintf("%s.%04x", prefix, randv); // open temp output file, and associate with CAutoFile fs::path pathTmp = GetDataDir() / tmpfn; FILE *file = fsbridge::fopen(pathTmp, "wb"); CAutoFile fileout(file, SER_DISK, CLIENT_VERSION); if (fileout.IsNull()) return error("%s: Failed to open file %s", __func__, pathTmp.string()); // Serialize if (!SerializeDB(fileout, data)) return false; FileCommit(fileout.Get()); fileout.fclose(); // replace existing file, if any, with new file if (!RenameOver(pathTmp, path)) return error("%s: Rename-into-place failed", __func__); return true; } template bool DeserializeDB(Stream& stream, Data& data, bool fCheckSum = true) { try { CHashVerifier verifier(&stream); // de-serialize file header (network specific magic number) and .. unsigned char pchMsgTmp[4]; verifier >> FLATDATA(pchMsgTmp); // ... verify the network matches ours if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp))) return error("%s: Invalid network magic number", __func__); // de-serialize data verifier >> data; // verify checksum if (fCheckSum) { uint256 hashTmp; stream >> hashTmp; if (hashTmp != verifier.GetHash()) { return error("%s: Checksum mismatch, data corrupted", __func__); } } } catch (const std::exception& e) { return error("%s: Deserialize or I/O error - %s", __func__, e.what()); } return true; } template bool DeserializeFileDB(const fs::path& path, Data& data) { // open input file, and associate with CAutoFile FILE *file = fsbridge::fopen(path, "rb"); CAutoFile filein(file, SER_DISK, CLIENT_VERSION); if (filein.IsNull()) return error("%s: Failed to open file %s", __func__, path.string()); return DeserializeDB(filein, data); } } CBanDB::CBanDB() { pathBanlist = GetDataDir() / "banlist.dat"; } bool CBanDB::Write(const banmap_t& banSet) { return SerializeFileDB("banlist", pathBanlist, banSet); } bool CBanDB::Read(banmap_t& banSet) { return DeserializeFileDB(pathBanlist, banSet); }