aboutsummaryrefslogtreecommitdiff
path: root/src/addrman.cpp
diff options
context:
space:
mode:
authorJohn Newbery <john@johnnewbery.com>2021-08-17 17:31:23 +0100
committerAmiti Uttarwar <amiti@uttarwar.org>2021-08-26 11:53:34 -0700
commit1622543cf42feb810d8ea9e7b3238d21f1427c17 (patch)
tree2215edd5aa9fbe0501740c44c94d64c0466ebc01 /src/addrman.cpp
parent4fc15d15667d9d9c4fb5515ce73c05b4596298ec (diff)
[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>
Diffstat (limited to 'src/addrman.cpp')
-rw-r--r--src/addrman.cpp108
1 files changed, 108 insertions, 0 deletions
diff --git a/src/addrman.cpp b/src/addrman.cpp
index edcf97f846..58feb39b1b 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -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);