mirror of
https://github.com/dashpay/dash.git
synced 2024-12-26 12:32:48 +01:00
4bb37eed2b
d9753383b9e1b61d19d98bcd1d66607f398c7e9f addrdb: Remove temporary files created in SerializeFileDB. Fixes non-determinism in unit tests. (practicalswift) Pull request description: Remove temporary files created in `SerializeFileDB` in case of errors. _Edit: Previously this was hit non-deterministically from the tests: that is no longer the case but the cleanup issue remains :-)_ ACKs for top commit: laanwj: code-review ACK d9753383b9e1b61d19d98bcd1d66607f398c7e9f Tree-SHA512: e72b74b8de411f433bd8bb354cacae07ab75a240db6232bc6a37802ccd8086bff5275ce3d196ddde033d8ab9e2794bb8f60eb83554af7ec2e9f91d6186cb4647
159 lines
4.2 KiB
C++
159 lines
4.2 KiB
C++
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
|
// Copyright (c) 2009-2015 The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#include <addrdb.h>
|
|
|
|
#include <addrman.h>
|
|
#include <chainparams.h>
|
|
#include <clientversion.h>
|
|
#include <hash.h>
|
|
#include <random.h>
|
|
#include <streams.h>
|
|
#include <tinyformat.h>
|
|
#include <util/system.h>
|
|
|
|
namespace {
|
|
|
|
template <typename Stream, typename Data>
|
|
bool SerializeDB(Stream& stream, const Data& data)
|
|
{
|
|
// Write and commit header, data
|
|
try {
|
|
CHashWriter hasher(SER_DISK, CLIENT_VERSION);
|
|
stream << Params().MessageStart() << data;
|
|
hasher << 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 <typename Data>
|
|
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()) {
|
|
fileout.fclose();
|
|
remove(pathTmp);
|
|
return error("%s: Failed to open file %s", __func__, pathTmp.string());
|
|
}
|
|
|
|
// Serialize
|
|
if (!SerializeDB(fileout, data)) {
|
|
fileout.fclose();
|
|
remove(pathTmp);
|
|
return false;
|
|
}
|
|
if (!FileCommit(fileout.Get())) {
|
|
fileout.fclose();
|
|
remove(pathTmp);
|
|
return error("%s: Failed to flush file %s", __func__, pathTmp.string());
|
|
}
|
|
fileout.fclose();
|
|
|
|
// replace existing file, if any, with new file
|
|
if (!RenameOver(pathTmp, path)) {
|
|
remove(pathTmp);
|
|
return error("%s: Rename-into-place failed", __func__);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
template <typename Stream, typename Data>
|
|
bool DeserializeDB(Stream& stream, Data& data, bool fCheckSum = true)
|
|
{
|
|
try {
|
|
CHashVerifier<Stream> verifier(&stream);
|
|
// de-serialize file header (network specific magic number) and ..
|
|
unsigned char pchMsgTmp[4];
|
|
verifier >> 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 <typename Data>
|
|
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);
|
|
}
|
|
|
|
CAddrDB::CAddrDB()
|
|
{
|
|
pathAddr = GetDataDir() / "peers.dat";
|
|
}
|
|
|
|
bool CAddrDB::Write(const CAddrMan& addr)
|
|
{
|
|
return SerializeFileDB("peers", pathAddr, addr);
|
|
}
|
|
|
|
bool CAddrDB::Read(CAddrMan& addr)
|
|
{
|
|
return DeserializeFileDB(pathAddr, addr);
|
|
}
|
|
|
|
bool CAddrDB::Read(CAddrMan& addr, CDataStream& ssPeers)
|
|
{
|
|
bool ret = DeserializeDB(ssPeers, addr, false);
|
|
if (!ret) {
|
|
// Ensure addrman is left in a clean state
|
|
addr.Clear();
|
|
}
|
|
return ret;
|
|
}
|