[addrman] Move CAddrMan::Serialize to cpp file

Reviewer hint: use `git diff --color-moved=dimmed-zebra
--color-moved-ws=ignore-all-space`

Co-authored-by: Amiti Uttarwar <amiti@uttarwar.org>
This commit is contained in:
John Newbery 2021-08-17 17:31:23 +01:00 committed by Amiti Uttarwar
parent 4fc15d1566
commit 1622543cf4
2 changed files with 109 additions and 101 deletions

View File

@ -94,6 +94,114 @@ CAddrMan::CAddrMan(bool deterministic, int32_t consistency_check_ratio)
}
}
template <typename Stream>
void CAddrMan::Serialize(Stream& s_) const
{
LOCK(cs);
/**
* Serialized format.
* * format version byte (@see `Format`)
* * lowest compatible format version byte. This is used to help old software decide
* whether to parse the file. For example:
* * Bitcoin Core version N knows how to parse up to format=3. If a new format=4 is
* introduced in version N+1 that is compatible with format=3 and it is known that
* version N will be able to parse it, then version N+1 will write
* (format=4, lowest_compatible=3) in the first two bytes of the file, and so
* version N will still try to parse it.
* * Bitcoin Core version N+2 introduces a new incompatible format=5. It will write
* (format=5, lowest_compatible=5) and so any versions that do not know how to parse
* format=5 will not try to read the file.
* * nKey
* * nNew
* * nTried
* * number of "new" buckets XOR 2**30
* * all new addresses (total count: nNew)
* * all tried addresses (total count: nTried)
* * for each new bucket:
* * number of elements
* * for each element: index in the serialized "all new addresses"
* * asmap checksum
*
* 2**30 is xorred with the number of buckets to make addrman deserializer v0 detect it
* as incompatible. This is necessary because it did not check the version number on
* deserialization.
*
* vvNew, vvTried, mapInfo, mapAddr and vRandom are never encoded explicitly;
* they are instead reconstructed from the other information.
*
* This format is more complex, but significantly smaller (at most 1.5 MiB), and supports
* changes to the ADDRMAN_ parameters without breaking the on-disk structure.
*
* We don't use SERIALIZE_METHODS since the serialization and deserialization code has
* very little in common.
*/
// Always serialize in the latest version (FILE_FORMAT).
OverrideStream<Stream> s(&s_, s_.GetType(), s_.GetVersion() | ADDRV2_FORMAT);
s << static_cast<uint8_t>(FILE_FORMAT);
// Increment `lowest_compatible` iff a newly introduced format is incompatible with
// the previous one.
static constexpr uint8_t lowest_compatible = Format::V3_BIP155;
s << static_cast<uint8_t>(INCOMPATIBILITY_BASE + lowest_compatible);
s << nKey;
s << nNew;
s << nTried;
int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
s << nUBuckets;
std::unordered_map<int, int> mapUnkIds;
int nIds = 0;
for (const auto& entry : mapInfo) {
mapUnkIds[entry.first] = nIds;
const CAddrInfo &info = entry.second;
if (info.nRefCount) {
assert(nIds != nNew); // this means nNew was wrong, oh ow
s << info;
nIds++;
}
}
nIds = 0;
for (const auto& entry : mapInfo) {
const CAddrInfo &info = entry.second;
if (info.fInTried) {
assert(nIds != nTried); // this means nTried was wrong, oh ow
s << info;
nIds++;
}
}
for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
int nSize = 0;
for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
if (vvNew[bucket][i] != -1)
nSize++;
}
s << nSize;
for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
if (vvNew[bucket][i] != -1) {
int nIndex = mapUnkIds[vvNew[bucket][i]];
s << nIndex;
}
}
}
// Store asmap checksum after bucket entries so that it
// can be ignored by older clients for backward compatibility.
uint256 asmap_checksum;
if (m_asmap.size() != 0) {
asmap_checksum = SerializeHash(m_asmap);
}
s << asmap_checksum;
}
// explicit instantiation
template void CAddrMan::Serialize(CHashWriter& s) const;
template void CAddrMan::Serialize(CAutoFile& s) const;
template void CAddrMan::Serialize(CDataStream& s) const;
CAddrInfo* CAddrMan::Find(const CNetAddr& addr, int* pnId)
{
AssertLockHeld(cs);

View File

@ -200,108 +200,8 @@ public:
// Read asmap from provided binary file
static std::vector<bool> DecodeAsmap(fs::path path);
/**
* Serialized format.
* * format version byte (@see `Format`)
* * lowest compatible format version byte. This is used to help old software decide
* whether to parse the file. For example:
* * Bitcoin Core version N knows how to parse up to format=3. If a new format=4 is
* introduced in version N+1 that is compatible with format=3 and it is known that
* version N will be able to parse it, then version N+1 will write
* (format=4, lowest_compatible=3) in the first two bytes of the file, and so
* version N will still try to parse it.
* * Bitcoin Core version N+2 introduces a new incompatible format=5. It will write
* (format=5, lowest_compatible=5) and so any versions that do not know how to parse
* format=5 will not try to read the file.
* * nKey
* * nNew
* * nTried
* * number of "new" buckets XOR 2**30
* * all new addresses (total count: nNew)
* * all tried addresses (total count: nTried)
* * for each new bucket:
* * number of elements
* * for each element: index in the serialized "all new addresses"
* * asmap checksum
*
* 2**30 is xorred with the number of buckets to make addrman deserializer v0 detect it
* as incompatible. This is necessary because it did not check the version number on
* deserialization.
*
* vvNew, vvTried, mapInfo, mapAddr and vRandom are never encoded explicitly;
* they are instead reconstructed from the other information.
*
* This format is more complex, but significantly smaller (at most 1.5 MiB), and supports
* changes to the ADDRMAN_ parameters without breaking the on-disk structure.
*
* We don't use SERIALIZE_METHODS since the serialization and deserialization code has
* very little in common.
*/
template <typename Stream>
void Serialize(Stream& s_) const
EXCLUSIVE_LOCKS_REQUIRED(!cs)
{
LOCK(cs);
// Always serialize in the latest version (FILE_FORMAT).
OverrideStream<Stream> s(&s_, s_.GetType(), s_.GetVersion() | ADDRV2_FORMAT);
s << static_cast<uint8_t>(FILE_FORMAT);
// Increment `lowest_compatible` iff a newly introduced format is incompatible with
// the previous one.
static constexpr uint8_t lowest_compatible = Format::V3_BIP155;
s << static_cast<uint8_t>(INCOMPATIBILITY_BASE + lowest_compatible);
s << nKey;
s << nNew;
s << nTried;
int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
s << nUBuckets;
std::unordered_map<int, int> mapUnkIds;
int nIds = 0;
for (const auto& entry : mapInfo) {
mapUnkIds[entry.first] = nIds;
const CAddrInfo &info = entry.second;
if (info.nRefCount) {
assert(nIds != nNew); // this means nNew was wrong, oh ow
s << info;
nIds++;
}
}
nIds = 0;
for (const auto& entry : mapInfo) {
const CAddrInfo &info = entry.second;
if (info.fInTried) {
assert(nIds != nTried); // this means nTried was wrong, oh ow
s << info;
nIds++;
}
}
for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
int nSize = 0;
for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
if (vvNew[bucket][i] != -1)
nSize++;
}
s << nSize;
for (int i = 0; i < ADDRMAN_BUCKET_SIZE; i++) {
if (vvNew[bucket][i] != -1) {
int nIndex = mapUnkIds[vvNew[bucket][i]];
s << nIndex;
}
}
}
// Store asmap checksum after bucket entries so that it
// can be ignored by older clients for backward compatibility.
uint256 asmap_checksum;
if (m_asmap.size() != 0) {
asmap_checksum = SerializeHash(m_asmap);
}
s << asmap_checksum;
}
void Serialize(Stream& s_) const EXCLUSIVE_LOCKS_REQUIRED(!cs);
template <typename Stream>
void Unserialize(Stream& s_)