p2p: Avoid InitError when downgrading peers.dat

fixes #24188
When downgrading, a peers.dat with a future version that has a minimum
required version larger than the downgraded version would cause an InitError.

This commit changes this behavior to overwrite the existing peers.dat with
a new empty one, while creating a backup in peers.dat.bak.
pull/826/head
junderw 3 years ago
parent 5b4b8f76f3
commit d41ed32153
No known key found for this signature in database
GPG Key ID: B256185D3A971908

@ -196,6 +196,15 @@ std::optional<bilingual_str> LoadAddrman(const std::vector<bool>& asmap, const A
addrman = std::make_unique<AddrMan>(asmap, /* deterministic */ false, /* consistency_check_ratio */ check_addrman); addrman = std::make_unique<AddrMan>(asmap, /* deterministic */ false, /* consistency_check_ratio */ check_addrman);
LogPrintf("Creating peers.dat because the file was not found (%s)\n", fs::quoted(fs::PathToString(path_addr))); LogPrintf("Creating peers.dat because the file was not found (%s)\n", fs::quoted(fs::PathToString(path_addr)));
DumpPeerAddresses(args, *addrman); DumpPeerAddresses(args, *addrman);
} catch (const InvalidAddrManVersionError&) {
if (!RenameOver(path_addr, (fs::path)path_addr + ".bak")) {
addrman = nullptr;
return strprintf(_("Failed to rename invalid peers.dat file. Please move or delete it and try again."));
}
// Addrman can be in an inconsistent state after failure, reset it
addrman = std::make_unique<AddrMan>(asmap, /* deterministic */ false, /* consistency_check_ratio */ check_addrman);
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)));
DumpPeerAddresses(args, *addrman);
} catch (const std::exception& e) { } catch (const std::exception& e) {
addrman = nullptr; addrman = nullptr;
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."), 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."),

@ -248,7 +248,7 @@ void AddrManImpl::Unserialize(Stream& s_)
s >> compat; s >> compat;
const uint8_t lowest_compatible = compat - INCOMPATIBILITY_BASE; const uint8_t lowest_compatible = compat - INCOMPATIBILITY_BASE;
if (lowest_compatible > FILE_FORMAT) { if (lowest_compatible > FILE_FORMAT) {
throw std::ios_base::failure(strprintf( throw InvalidAddrManVersionError(strprintf(
"Unsupported format of addrman database: %u. It is compatible with formats >=%u, " "Unsupported format of addrman database: %u. It is compatible with formats >=%u, "
"but the maximum supported by this version of %s is %u.", "but the maximum supported by this version of %s is %u.",
uint8_t{format}, uint8_t{lowest_compatible}, PACKAGE_NAME, uint8_t{FILE_FORMAT})); uint8_t{format}, uint8_t{lowest_compatible}, PACKAGE_NAME, uint8_t{FILE_FORMAT}));

@ -17,6 +17,12 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
class InvalidAddrManVersionError : public std::ios_base::failure
{
public:
InvalidAddrManVersionError(std::string msg) : std::ios_base::failure(msg) { }
};
class AddrManImpl; class AddrManImpl;
/** Default for -checkaddrman */ /** Default for -checkaddrman */

@ -68,17 +68,16 @@ class AddrmanTest(BitcoinTestFramework):
self.start_node(0, extra_args=["-checkaddrman=1"]) self.start_node(0, extra_args=["-checkaddrman=1"])
assert_equal(self.nodes[0].getnodeaddresses(), []) assert_equal(self.nodes[0].getnodeaddresses(), [])
self.log.info("Check that addrman from future cannot be read") self.log.info("Check that addrman from future is overwritten with new addrman")
self.stop_node(0) self.stop_node(0)
write_addrman(peers_dat, lowest_compatible=111) write_addrman(peers_dat, lowest_compatible=111)
self.nodes[0].assert_start_raises_init_error( assert_equal(os.path.exists(peers_dat + ".bak"), False)
expected_msg=init_error( with self.nodes[0].assert_debug_log([
"Unsupported format of addrman database: 1. It is compatible with " f'Creating new peers.dat because the file version was not compatible ("{peers_dat}"). Original backed up to peers.dat.bak',
"formats >=111, but the maximum supported by this version of " ]):
f"{self.config['environment']['PACKAGE_NAME']} is 4.: (.+)" self.start_node(0)
), assert_equal(self.nodes[0].getnodeaddresses(), [])
match=ErrorMatch.FULL_REGEX, assert_equal(os.path.exists(peers_dat + ".bak"), True)
)
self.log.info("Check that corrupt addrman cannot be read (EOF)") self.log.info("Check that corrupt addrman cannot be read (EOF)")
self.stop_node(0) self.stop_node(0)

Loading…
Cancel
Save